From bd74e5f3b2edd7f30212ef5a45d5c0f93bb0ad4e Mon Sep 17 00:00:00 2001 From: Matt Blenkinsop Date: Mon, 24 Jul 2023 13:53:22 +0000 Subject: [PATCH] Bug 34355: Add cronjob and required methods This patch adds a cronjob to take a marc file from the Koha file directory system and import it before creating order lines Test plan: This test plan involves running a cronjob, not sure how easy this is in the sandboxes 1) In system preferences, click Search and then select the Acquisitions option from the left hand menu 2) Enable MarcOrderingAutomation 3) Paste the following into MarcFieldsToOrder price: 975$p quantity: 975$q budget_code: 975$h 4) Paste the following into MarcItemFieldsToOrder homebranch: 949$a holdingbranch: 949$b itype: 949$y nonpublic_note: 949$x public_note: 949$z loc: 949$c ccode: 949$8 notforloan: 949$7 uri: 949$u copyno: 949$t price: 949$g replacementprice: 949$v itemcallnumber: 949$o quantity: 949$k budget_code: 949$l Now save the sysprefs 5) In the administration homepage, under Acquisition parameters there should now be a link called "MARC order accounts" 6) Click on this and click the New account button 7) Choose a vendor and a budget 8) Enter a description 9) Enter the following in download directory - "/var/lib/koha/kohadev/tmp/koha_kohadev_upload" 10) Select any record matching settings you want (not important for the test plan, this uses the same code as the marc file staging that already exists in Koha) 11) Check Yes under Check for embedded item record data 12) Click submit 13) We now need to upload a MARC file into the directory that we put in the account. The easiest way to do this is through the marc staging tool 14) Navigate to Cataloging > Stage MARC records for import 15) Upload the file attached to this bug using the Choose file button 16) Click Upload file. 17) Leave the page without completing the new form that appears, we don't want to stage this file. The file we uploaded is now in the directory ready for the cronjob to process as if it had been transferred via SFTP. 18) In the CLI run, perl misc/cronjobs/marc_ordering_process.pl -v -c 19) The logging should show that the file has been processed for that account 20) Navigate to Acquisitions 21) Search for the Vendor that you put in the MARC ordering account 22) There should be a basket created on the vendor with the name of the file you uploaded (there will also be a reference at the start e.g. ea2323966faef2c59a6056dbd1f7d658_filename.marcxml. This is because we used the marc staging tool to upload the file and that adds a reference to filenames. This will not appear when using files from an SFTP location). 23) Click in the basket 24) There should be three orderlines, complete with accounting details that have been mapped from the file. One line should have a fund of Fund 1_2, quantity of 4 and a replacement price of 6.75, one should have Secondary fund, 2, 6.40 and one should have Main fund,2, 6.30 Signed-off-by: Andrew Fuerste Henry Signed-off-by: Nick Clemens --- Koha/MarcOrder.pm | 414 +++++++++++++++++++++---- misc/cronjobs/marc_ordering_process.pl | 134 ++++++++ 2 files changed, 483 insertions(+), 65 deletions(-) create mode 100755 misc/cronjobs/marc_ordering_process.pl diff --git a/Koha/MarcOrder.pm b/Koha/MarcOrder.pm index 4bb58c41cf0..8373c99c897 100644 --- a/Koha/MarcOrder.pm +++ b/Koha/MarcOrder.pm @@ -19,6 +19,7 @@ package Koha::MarcOrder; use Modern::Perl; use Try::Tiny qw( catch try ); +use Net::FTP; use base qw(Koha::Object); @@ -47,7 +48,6 @@ use C4::Biblio qw( AddBiblio GetMarcFromKohaField TransformHtmlToXml - GetMarcQuantity ); use C4::Items qw( AddItemFromMarc ); use C4::Budgets qw( GetBudgetByCode ); @@ -70,6 +70,95 @@ Koha::MarcOrder - Koha Marc Order Object class =cut +=head3 create_order_lines_from_file + + my $result = Koha::MarcOrder->create_order_lines_from_file($args); + + Controller for file staging, basket creation and order line creation when using the cronjob in marc_ordering_process.pl + +=cut + +sub create_order_lines_from_file { + my ( $self, $args ) = @_; + + my $filename = $args->{filename}; + my $filepath = $args->{filepath}; + my $profile = $args->{profile}; + my $agent = $args->{agent}; + + my $success; + my $error; + + my $vendor_id = $profile->vendor_id; + my $budget_id = $profile->budget_id; + + my $vendor_record = Koha::Acquisition::Booksellers->find( { id => $vendor_id } ); + + my $basket_id = _create_basket_for_file( + { + filename => $filename, + vendor_id => $vendor_id + } + ); + + my $format = index( $filename, '.mrc' ) != -1 ? 'ISO2709' : 'MARCXML'; + my $params = { + record_type => $profile->record_type, + encoding => $profile->encoding, + format => $format, + filepath => $filepath, + filename => $filename, + comments => undef, + parse_items => $profile->parse_items, + matcher_id => $profile->matcher_id, + overlay_action => $profile->overlay_action, + nomatch_action => $profile->nomatch_action, + item_action => $profile->item_action, + }; + + try { + my $import_batch_id = _stage_file($params); + + my $import_records = Koha::Import::Records->search( + { + import_batch_id => $import_batch_id, + } + ); + + while( my $import_record = $import_records->next ){ + my $result = add_biblio_from_import_record({ + import_batch_id => $import_batch_id, + import_record => $import_record, + matcher_id => $params->{matcher_id}, + overlay_action => $params->{overlay_action}, + agent => $agent, + }); + warn "Duplicates found in $result->{duplicates_in_batch}, record was skipped." if $result->{duplicates_in_batch}; + next if $result->{skip}; + + my $order_line_details = add_items_from_import_record( + { + record_result => $result->{record_result}, + basket_id => $basket_id, + vendor => $vendor_record, + budget_id => $budget_id, + agent => $agent, + } + ); + } + SetImportBatchStatus( $import_batch_id, 'imported' ) + if Koha::Import::Records->search( { import_batch_id => $import_batch_id, status => 'imported' } )->count == + Koha::Import::Records->search( { import_batch_id => $import_batch_id } )->count; + + $success = 1; + } catch { + $success = 0; + $error = $_; + }; + + return $success ? { success => 1, error => '' } : { success => 0, error => $error }; +} + =head3 import_record_and_create_order_lines my $result = Koha::MarcOrder->import_record_and_create_order_lines($args); @@ -82,7 +171,7 @@ sub import_record_and_create_order_lines { my ( $self, $args ) = @_; my $import_batch_id = $args->{import_batch_id}; - my $import_record_id_selected = $args->{import_record_id_selected} || (); + my @import_record_id_selected = $args->{import_record_id_selected} || (); my $matcher_id = $args->{matcher_id}; my $overlay_action = $args->{overlay_action}; my $import_record = $args->{import_record}; @@ -125,6 +214,121 @@ sub import_record_and_create_order_lines { }; } +=head3 _create_basket_for_file + + my $basket_id = _create_basket_for_file({ + filename => $filename, + vendor_id => $vendor_id + }); + + Creates a basket ready to receive order lines based on the imported file + +=cut + +sub _create_basket_for_file { + my ($args) = @_; + + my $filename = $args->{filename}; + my $vendor_id = $args->{vendor_id}; + + # aqbasketname.basketname has a max length of 50 characters so long file names will need to be truncated + my $basketname = length($filename) > 50 ? substr( $filename, 0, 50 ) : $filename; + + my $basketno = NewBasket( + $vendor_id, 0, $basketname, q{}, + q{} . q{} + ); + + return $basketno; +} + +=head3 _stage_file + + $file->_stage_file($params) + + Stages a file directly using parameters from a marc ordering account and without using the background job + This function is a mirror of Koha::BackgroundJob::StageMARCForImport->process but with the background job functionality removed + +=cut + +sub _stage_file { + my ($args) = @_; + + my $record_type = $args->{record_type}; + my $encoding = $args->{encoding}; + my $format = $args->{format}; + my $filepath = $args->{filepath}; + my $filename = $args->{filename}; + my $marc_modification_template = $args->{marc_modification_template}; + my $comments = $args->{comments}; + my $parse_items = $args->{parse_items}; + my $matcher_id = $args->{matcher_id}; + my $overlay_action = $args->{overlay_action}; + my $nomatch_action = $args->{nomatch_action}; + my $item_action = $args->{item_action}; + + my ( $batch_id, $num_valid, $num_items, @import_errors ); + my $num_with_matches = 0; + my $checked_matches = 0; + my $matcher_failed = 0; + my $matcher_code = ""; + + my $schema = Koha::Database->new->schema; + try { + $schema->storage->txn_begin; + + my ( $errors, $marcrecords ); + if ( $format eq 'MARCXML' ) { + ( $errors, $marcrecords ) = C4::ImportBatch::RecordsFromMARCXMLFile( $filepath, $encoding ); + } elsif ( $format eq 'ISO2709' ) { + ( $errors, $marcrecords ) = C4::ImportBatch::RecordsFromISO2709File( + $filepath, $record_type, + $encoding + ); + } else { # plugin based + $errors = []; + $marcrecords = C4::ImportBatch::RecordsFromMarcPlugin( + $filepath, $format, + $encoding + ); + } + + ( $batch_id, $num_valid, $num_items, @import_errors ) = BatchStageMarcRecords( + $record_type, $encoding, + $marcrecords, $filename, + $marc_modification_template, $comments, + '', $parse_items, + 0 + ); + + if ($matcher_id) { + my $matcher = C4::Matcher->fetch($matcher_id); + if ( defined $matcher ) { + $checked_matches = 1; + $matcher_code = $matcher->code(); + $num_with_matches = BatchFindDuplicates( $batch_id, $matcher, 10 ); + SetImportBatchMatcher( $batch_id, $matcher_id ); + SetImportBatchOverlayAction( $batch_id, $overlay_action ); + SetImportBatchNoMatchAction( $batch_id, $nomatch_action ); + SetImportBatchItemAction( $batch_id, $item_action ); + $schema->storage->txn_commit; + } else { + $matcher_failed = 1; + $schema->storage->txn_rollback; + } + } else { + $schema->storage->txn_commit; + } + + return $batch_id; + } catch { + warn $_; + $schema->storage->txn_rollback; + die "Something terrible has happened!" + if ( $_ =~ /Rollback failed/ ); # TODO Check test: Rollback failed + }; +} + =head3 _get_syspref_mappings my $syspref_info = _get_syspref_mappings( $marcrecord, $syspref_name ); @@ -234,7 +438,7 @@ sub add_biblio_from_import_record { my ($args) = @_; my $import_batch_id = $args->{import_batch_id}; - my $import_record_id_selected = $args->{import_record_id_selected} || (); + my @import_record_id_selected = $args->{import_record_id_selected} || (); my $matcher_id = $args->{matcher_id}; my $overlay_action = $args->{overlay_action}; my $import_record = $args->{import_record}; @@ -247,7 +451,7 @@ sub add_biblio_from_import_record { record_result => 0, duplicates_in_batch => 0, skip => 1 - } if not grep { $_ eq $import_record->import_record_id } @{$import_record_id_selected}; + } if not grep { $_ eq $import_record->import_record_id } @import_record_id_selected; } my $marcrecord = $import_record->get_marc_record || die "Couldn't translate marc information"; @@ -333,29 +537,13 @@ sub add_items_from_import_record { my $marc_fields_to_order = _get_syspref_mappings( $marcrecord, 'MarcFieldsToOrder' ); my $marc_item_fields_to_order = _get_syspref_mappings( $marcrecord, 'MarcItemFieldsToOrder' ); - my $item_fields = { - homebranch => $marc_item_fields_to_order->{homebranch}, - holdingbranch => $marc_item_fields_to_order->{holdingbranch}, - itype => $marc_item_fields_to_order->{itype}, - nonpublic_note => $marc_item_fields_to_order->{nonpublic_note}, - public_note => $marc_item_fields_to_order->{public_note}, - loc => $marc_item_fields_to_order->{loc}, - ccode => $marc_item_fields_to_order->{ccode}, - notforloan => $marc_item_fields_to_order->{notforloan}, - uri => $marc_item_fields_to_order->{uri}, - copyno => $marc_item_fields_to_order->{copyno}, - quantity => $marc_item_fields_to_order->{quantity}, - price => $marc_item_fields_to_order->{price}, - replacementprice => $marc_item_fields_to_order->{replacementprice}, - itemcallnumber => $marc_item_fields_to_order->{itemcallnumber}, - budget_code => $marc_item_fields_to_order->{budget_code}, - c_quantity => $marc_fields_to_order->{quantity}, - c_budget_code => $marc_fields_to_order->{budget_code}, - c_price => $marc_fields_to_order->{price}, - c_discount => $marc_fields_to_order->{discount}, - c_sort1 => $marc_fields_to_order->{sort1}, - c_sort2 => $marc_fields_to_order->{sort2}, - }; + my $item_fields = _create_item_fields_from_syspref( + { + marc_fields_to_order => $marc_fields_to_order, + marc_item_fields_to_order => $marc_item_fields_to_order, + budget_id => $budget_id + } + ); my $order_line_fields = parse_input_into_order_line_fields( { @@ -405,6 +593,7 @@ sub add_items_from_import_record { } } + =head3 import_batches_list Fetches import batches matching the batch to be added to the basket and returns these to the template @@ -668,7 +857,6 @@ my $order_line_fields = parse_input_into_order_line_fields( } ); - =cut sub parse_input_into_order_line_fields { @@ -682,48 +870,45 @@ sub parse_input_into_order_line_fields { my $fields = $args->{fields}; my $marcrecord = $args->{marcrecord}; - my $quantity = $fields->{quantity} || 1; - my @homebranches = $client ? @{ $fields->{homebranches} } : ( ( $fields->{homebranch} ) x $quantity ); - my @holdingbranches = $client ? @{ $fields->{holdingbranches} } : ( ( $fields->{holdingbranch} ) x $quantity ); - my @itypes = $client ? @{ $fields->{itypes} } : ( ( $fields->{itype} ) x $quantity ); - my @nonpublic_notes = $client ? @{ $fields->{nonpublic_notes} } : ( ( $fields->{nonpublic_note} ) x $quantity ); - my @public_notes = $client ? @{ $fields->{public_notes} } : ( ( $fields->{public_note} ) x $quantity ); - my @locs = $client ? @{ $fields->{locs} } : ( ( $fields->{loc} ) x $quantity ); - my @ccodes = $client ? @{ $fields->{ccodes} } : ( ( $fields->{ccode} ) x $quantity ); - my @notforloans = $client ? @{ $fields->{notforloans} } : ( ( $fields->{notforloan} ) x $quantity ); - my @uris = $client ? @{ $fields->{uris} } : ( ( $fields->{uri} ) x $quantity ); - my @copynos = $client ? @{ $fields->{copynos} } : ( ( $fields->{copyno} ) x $quantity ); - my @itemprices = $client ? @{ $fields->{itemprices} } : ( ( $fields->{price} ) x $quantity ); - my @replacementprices = - $client ? @{ $fields->{replacementprices} } : ( ( $fields->{replacementprice} ) x $quantity ); - my @itemcallnumbers = $client ? @{ $fields->{itemcallnumbers} } : ( ( $fields->{itemcallnumber} ) x $quantity ); + my $quantity = $fields->{quantity} || 1; + my @homebranches = $fields->{homebranches} ? @{ $fields->{homebranches} } : (); + my @holdingbranches = $fields->{holdingbranches} ? @{ $fields->{holdingbranches} } : (); + my @itypes = $fields->{itypes} ? @{ $fields->{itypes} } : (); + my @nonpublic_notes = $fields->{nonpublic_notes} ? @{ $fields->{nonpublic_notes} } : (); + my @public_notes = $fields->{public_notes} ? @{ $fields->{public_notes} } : (); + my @locs = $fields->{locs} ? @{ $fields->{locs} } : (); + my @ccodes = $fields->{ccodes} ? @{ $fields->{ccodes} } : (); + my @notforloans = $fields->{notforloans} ? @{ $fields->{notforloans} } : (); + my @uris = $fields->{uris} ? @{ $fields->{uris} } : (); + my @copynos = $fields->{copynos} ? @{ $fields->{copynos} } : (); + my @itemprices = $fields->{itemprices} ? @{ $fields->{itemprices} } : (); + my @replacementprices = $fields->{replacementprices} ? @{ $fields->{replacementprices} } : (); + my @itemcallnumbers = $fields->{itemcallnumbers} ? @{ $fields->{itemcallnumbers} } : (); my @coded_location_qualifiers = - $client ? @{ $fields->{coded_location_qualifiers} } : ( ( $fields->{coded_location_qualifier} ) x $quantity ); - my @barcodes = $client ? @{ $fields->{barcodes} } : ( ( $fields->{barcode} ) x $quantity ); - my @enumchrons = $client ? @{ $fields->{enumchrons} } : ( ( $fields->{enumchron} ) x $quantity ); - my $c_quantity = $client ? $fields->{c_quantity} : $fields->{c_quantity}; - my $c_budget_id = $client ? $fields->{c_budget_id} : $fields->{c_budget_id}; - my $c_discount = $client ? $fields->{c_discount} : $fields->{c_discount}; - my $c_sort1 = $client ? $fields->{c_sort1} : $fields->{c_sort1}; - my $c_sort2 = $client ? $fields->{c_sort2} : $fields->{c_sort2}; - my $c_replacement_price = $client ? $fields->{c_replacement_price} : $fields->{c_replacement_price}; - my $c_price = $client ? $fields->{c_price} : $fields->{c_price}; + $fields->{coded_location_qualifiers} ? @{ $fields->{coded_location_qualifiers} } : (); + my @barcodes = $fields->{barcodes} ? @{ $fields->{barcodes} } : (); + my @enumchrons = $fields->{enumchrons} ? @{ $fields->{enumchrons} } : (); + my @budget_codes = $fields->{budget_codes} ? @{ $fields->{budget_codes} } : (); + my $c_quantity = $fields->{c_quantity}; + my $c_budget_id = $fields->{c_budget_id}; + my $c_discount = $fields->{c_discount}; + my $c_sort1 = $fields->{c_sort1}; + my $c_sort2 = $fields->{c_sort2}; + my $c_replacement_price = $fields->{c_replacement_price}; + my $c_price = $fields->{c_price}; # If using the cronjob, we want to default to the account budget if not mapped on the record - my $item_budget_id; - if ( !$client && ( $fields->{budget_code} || $fields->{c_budget_code} ) ) { - my $budget_code = $fields->{budget_code} || $fields->{c_budget_code}; - my $item_budget = GetBudgetByCode($budget_code); - if ($item_budget) { - $item_budget_id = $item_budget->{budget_id}; - } else { - $item_budget_id = $budget_id; + if ( !$client && ( !@budget_codes || scalar(@budget_codes) == 0 ) ) { + for ( 1 .. $quantity ) { + my $item_budget = GetBudgetByCode($c_budget_id); + if ($item_budget) { + push( @budget_codes, $item_budget ); + } else { + push( @budget_codes, $budget_id ); + } } - } else { - $item_budget_id = $budget_id; } - my @budget_codes = $client ? @{ $fields->{budget_codes} } : ($item_budget_id); - my $loop_limit = $client ? scalar(@homebranches) : $quantity; + my $loop_limit = $quantity; my $order_line_fields = { biblionumber => $biblionumber, @@ -959,4 +1144,103 @@ sub _format_price_to_CurrencyFormat_syspref { return $price; } +=head3 _create_item_fields_from_syspref + +Takes the two sysprefs and returns the item fields required to process and create orderlines + +my $item_fields = _create_item_fields_from_syspref( + { + marc_fields_to_order => $marc_fields_to_order, + marc_item_fields_to_order => $marc_item_fields_to_order + } +); + +=cut + +sub _create_item_fields_from_syspref { + my ($args) = @_; + + my $marc_item_fields_to_order = $args->{marc_item_fields_to_order}; + my $marc_fields_to_order = $args->{marc_fields_to_order}; + my $budget_id = $args->{budget_id}; + + my @homebranches = (); + my @holdingbranches = (); + my @itypes = (); + my @nonpublic_notes = (); + my @public_notes = (); + my @locs = (); + my @ccodes = (); + my @notforloans = (); + my @uris = (); + my @copynos = (); + my @budget_codes = (); + my @itemprices = (); + my @replacementprices = (); + my @itemcallnumbers = (); + + foreach my $infoset (@$marc_item_fields_to_order) { + my $quantity = $infoset->{quantity} || 1; + for ( my $i = 0 ; $i < $quantity ; $i++ ) { + my $budget_code; + if ( !$infoset->{budget_code} ) { + if ( $marc_fields_to_order->{budget_code} ) { + $budget_code = $marc_fields_to_order->{budget_code}; + } + } else { + $budget_code = $infoset->{budget_code}; + } + + my $item_budget_id; + my $item_budget = GetBudgetByCode($budget_code); + if ($item_budget) { + $item_budget_id = $item_budget->{budget_id}; + } else { + $item_budget_id = $budget_id; + } + + push @homebranches, $infoset->{homebranch}; + push @holdingbranches, $infoset->{holdingbranch}; + push @itypes, $infoset->{itype}; + push @nonpublic_notes, $infoset->{nonpublic_note}; + push @public_notes, $infoset->{public_note}; + push @locs, $infoset->{loc}; + push @ccodes, $infoset->{ccode}; + push @notforloans, $infoset->{notforloan}; + push @uris, $infoset->{uri}; + push @copynos, $infoset->{copyno}; + push @budget_codes, $item_budget_id; + push @itemprices, $infoset->{price}; + push @replacementprices, $infoset->{replacementprice}; + push @itemcallnumbers, $infoset->{itemcallnumber}; + } + } + + my $item_fields = { + quantity => scalar(@homebranches), + homebranches => \@homebranches, + holdingbranches => \@holdingbranches, + itypes => \@itypes, + nonpublic_notes => \@nonpublic_notes, + public_notes => \@public_notes, + locs => \@locs, + ccodes => \@ccodes, + notforloans => \@notforloans, + uris => \@uris, + copynos => \@copynos, + budget_codes => \@budget_codes, + itemprices => \@itemprices, + replacementprices => \@replacementprices, + itemcallnumbers => \@itemcallnumbers, + c_quantity => $marc_fields_to_order->{quantity}, + c_budget_code => $marc_fields_to_order->{budget_code}, + c_price => $marc_fields_to_order->{price}, + c_discount => $marc_fields_to_order->{discount}, + c_sort1 => $marc_fields_to_order->{sort1}, + c_sort2 => $marc_fields_to_order->{sort2}, + }; + + return $item_fields; +} + 1; diff --git a/misc/cronjobs/marc_ordering_process.pl b/misc/cronjobs/marc_ordering_process.pl new file mode 100755 index 00000000000..301579dcd19 --- /dev/null +++ b/misc/cronjobs/marc_ordering_process.pl @@ -0,0 +1,134 @@ + +#!/usr/bin/perl + +# This file is part of Koha. +# +# Copyright (C) 2023 PTFS Europe Ltd +# +# 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 . + +=head1 NAME + +marc_ordering_process.pl - cron script to retrieve marc files and create order lines + +=head1 SYNOPSIS + +./marc_ordering_process.pl [-c|--confirm] [-v|--verbose] + +or, in crontab: +# Once every day +0 3 * * * marc_ordering_process.pl -c + +=head1 DESCRIPTION + +This script searches for new marc files in an SFTP location +If there are new files, it stages those files, adds bilbios/items and creates order lines + +=head1 OPTIONS + +=over + +=item B<-v|--verbose> + +Print report to standard out. + +=item B<-c|--confirm> + +Without this parameter no changes will be made + +=back + +=cut + +use Modern::Perl; +use Pod::Usage qw( pod2usage ); +use Getopt::Long qw( GetOptions ); +use File::Copy qw( copy move ); + +use Koha::Script -cron; +use Koha::MarcOrder; +use Koha::MarcOrderAccounts; + +use C4::Log qw( cronlogaction ); + +my $command_line_options = join( " ", @ARGV ); + +my ( $help, $verbose, $confirm ); +GetOptions( + 'h|help' => \$help, + 'v|verbose' => \$verbose, + 'c|confirm' => \$confirm, +) || pod2usage(1); + +pod2usage(0) if $help; + +cronlogaction( { info => $command_line_options } ); + +$verbose = 1 unless $verbose or $confirm; +print "Test run only\n" unless $confirm; + +print "Fetching marc ordering accounts\n" if $verbose; +my @accounts = Koha::MarcOrderAccounts->search( + {}, + { join => [ 'vendor', 'budget' ] } +)->as_list; + +if ( scalar(@accounts) == 0 ) { + print "No accounts found - you must create a Marc order account for this cronjob to run\n" if $verbose; +} + +foreach my $acct (@accounts) { + if ($verbose) { + say sprintf "Starting marc ordering process for %s", $acct->vendor->name; + say sprintf "Looking for new files in %s", $acct->download_directory; + } + + my $working_dir = $acct->download_directory; + opendir my $dir, $working_dir or die "Can't open filepath"; + my @files = grep { /\.(mrc|marcxml|mrk)/i } readdir $dir; + closedir $dir; + print "No new files found\n" if scalar(@files) == 0; + + my $files_processed = 0; + + foreach my $filename (@files) { + my $full_path = "$working_dir/$filename"; + my $args = { + filename => $filename, + filepath => $full_path, + profile => $acct, + agent => 'cron' + }; + if ( $acct->match_field && $acct->match_value ) { + my $file_match = Koha::MarcOrder->match_file_to_account($args); + next if !$file_match; + } + if ($confirm) { + say sprintf "Creating order lines from file %s", $filename if $verbose; + my $result = Koha::MarcOrder->create_order_lines_from_file($args); + if ( $result->{success} ) { + $files_processed++; + say sprintf "Successfully processed file: %s", $filename if $verbose; + unlink $full_path; + } else { + say sprintf "Error processing file: %s", $filename if $verbose; + say sprintf "Error message: %s", $result->{error} if $verbose; + } + } + } + say sprintf "%s files processed", $files_processed unless $files_processed == 0; + print "Moving to next account\n\n"; +} +print "Process complete\n"; +cronlogaction( { action => 'End', info => "COMPLETED" } ); -- 2.39.5