From 6f271e9827009a25f90a3910f6a9cd58fc463a0d Mon Sep 17 00:00:00 2001
From: Brendan Lawlor <blawlor@clamsnet.org>
Date: Wed, 13 Nov 2024 21:26:43 +0000
Subject: [PATCH] Bug 35654: Add option to delete_items.pl cronjob to delete
 empty bibs

This patch adds a new option to the delete_items cronjob

When --del_bibs is set, bib records will be deleted
if the last item is deleted.

The following plan assumes default ktd data.

To test:
1. Apply patch
2. Check the holdings for bib #115 and see 3 items
  http://localhost:8081/cgi-bin/koha/catalogue/detail.pl?biblionumber=115
2. Run the cron with the following flags
  perl ./misc/cronjobs/delete_items.pl --where "biblionumber=115 and homebranch ='MPL'" --verbose --del_bibs --commit
3. Notice in the output the count of current items on the bib record:
  Where statement:  where biblionumber=115 and homebranch='MPL'
  Deleting empty bib records!
  Deleting item '237' (of 3)
  Deleting item '238' (of 2)
4. Confirm the two Midway items were deleted from bib #115, and the bib still exists with one item
4. Run the cron again but change the the --where flag to delete all the items from bib #115
  perl ./misc/cronjobs/delete_items.pl --where "biblionumber=115" --verbose --del_bibs --commit
5. Notice in the output the bib is deleted after the last item is deleted
  Where statement:  where biblionumber=115
  Deleting empty bib records!
  Deleting item '239' (of 1)
  Last item deleted - deleting bib '115'
8. Confirm the bib #115 was deleted
9. Add some more items and test with some other --where parameters
10. Test with and without --commit and --del_bibs, test the --help flag

Sponsored-by: CLAMS
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
---
 misc/cronjobs/delete_items.pl | 94 ++++++++++++++++++-----------------
 1 file changed, 49 insertions(+), 45 deletions(-)

diff --git a/misc/cronjobs/delete_items.pl b/misc/cronjobs/delete_items.pl
index 0187cfb1aa..ebf2738acc 100755
--- a/misc/cronjobs/delete_items.pl
+++ b/misc/cronjobs/delete_items.pl
@@ -21,66 +21,66 @@ use Getopt::Long qw( GetOptions );
 use Pod::Usage   qw( pod2usage );
 
 use Koha::Script -cron;
-
-use C4::Context;
+use C4::Biblio qw( DelBiblio );
 use Koha::Items;
 
-my $dbh = C4::Context->dbh();
-
-my $query = { target_items => q|SELECT itemnumber, biblionumber from items| };
-
-my $GLOBAL = { query => $query, sth => {} };
-
-my $OPTIONS = {
-    where => [],
-    flags => {
-        verbose => '', commit => ''
-        , help    => ''
-        , manual  => ''
-        , version => ''
-    }
-};
+my @where          = ();
+my $verbose        = 0;
+my $help           = 0;
+my $manual         = 0;
+my $commit         = 0;
+my $delete_biblios = 0;
 
 GetOptions(
-    'where=s' => $OPTIONS->{where}, 'v|verbose' => sub { $OPTIONS->{flags}->{verbose} = 1 }
-    , 'V|version' => sub { $OPTIONS->{flags}->{version} = 1 }
-    , 'h|help'    => sub { $OPTIONS->{flags}->{help}    = 1 }
-    , 'm|manual'  => sub { $OPTIONS->{flags}->{manual}  = 1 }
-    , 'c|commit'  => sub { $OPTIONS->{flags}->{commit}  = 1 }    # aka DO-EET!
+    'where=s'  => \@where, 'v|verbose' => \$verbose,
+    'h|help'   => \$help,
+    'm|manual' => \$manual,
+    'c|commit' => \$commit,
+    'del_bibs' => \$delete_biblios
 );
 
-my @where = @{ $OPTIONS->{where} };
+pod2usage( -verbose => 2 )                                                            if $manual;
+pod2usage( -verbose => 1 )                                                            if $help;
+pod2usage( -verbose => 1, -message => 'You must supply at least one --where option' ) if scalar @where == 0;
 
-pod2usage( -verbose => 2 )                                                       if $OPTIONS->{flags}->{manual};
-pod2usage( -verbose => 1 )                                                       if $OPTIONS->{flags}->{help};
-pod2usage( -verbose => 1 -msg => 'You must supply at least one --where option' ) if scalar @where == 0;
+my $where_clause = join( " AND ", @where );
 
-sub verbose {
-    say @_ if $OPTIONS->{flags}->{verbose};
+$verbose && say "Where statement: $where_clause";
+if ($delete_biblios) {
+    $verbose && say "Deleting bibliographic records when all items are deleted!";
 }
 
-my $where_clause = ' where ' . join( " and ", @where );
-
-verbose "Where statement: $where_clause";
+print "Test run only! No data will be deleted.\n" unless $commit;
+my $deleted_string = $commit ? "Deleted" : "Would have deleted";
 
-# FIXME Use Koha::Items instead
-$GLOBAL->{sth}->{target_items} = $dbh->prepare( $query->{target_items} . $where_clause );
-$GLOBAL->{sth}->{target_items}->execute();
+my $items = Koha::Items->search( \$where_clause );
 
-DELITEM: while ( my $item = $GLOBAL->{sth}->{target_items}->fetchrow_hashref() ) {
+DELITEM: while ( my $item = $items->next ) {
 
-    my $item_object    = Koha::Items->find( $item->{itemnumber} );
-    my $safe_to_delete = $item_object->safe_to_delete;
+    my $safe_to_delete = $item->safe_to_delete;
+    my $error;
     if ($safe_to_delete) {
-        $item_object->safe_delete
-            if $OPTIONS->{flags}->{commit};
-        verbose "Deleting '$item->{itemnumber}'";
+        my $holdings_count = $item->biblio->items->count - 1;
+        $item->safe_delete
+            if $commit;
+        $verbose && say "$deleted_string item " . $item->itemnumber . " ($holdings_count items remain on record)";
+
+        if ( $delete_biblios && $holdings_count == 0 ) {    # aka DO-EET for empty bibs!
+            $error = &DelBiblio( $item->biblionumber ) if $commit;
+            if ($error) {
+                $verbose && say "Could not delete bib " . $item->biblionumber . ": $error";
+            } else {
+                $verbose && say "No items remaining. $deleted_string bibliographic record " . $item->biblionumber;
+            }
+        }
     } else {
-        verbose sprintf "Item '%s' (Barcode: '%s', Title: '%s') not deleted: %s",
-            $item->{itemnumber},
-            $item_object->barcode,
-            $item_object->biblio->title,
-            @{ $safe_to_delete->messages }[0]->message;
+        say sprintf(
+            "Item '%s' (Barcode: '%s', Title: '%s') cannot deleted: %s",
+            $item->itemnumber,
+            $item->barcode,
+            $item->biblio->title,
+            @{ $safe_to_delete->messages }[0]->message
+        ) if $verbose;
     }
 }
 
@@ -123,6 +123,10 @@ clause querying the items table. These are joined by C<AND>.
 
 No items will be deleted unless the C<--commit> flag is present.
 
+=item B<--del_bibs>
+
+Deletes the bibliographic record if the last item is deleted.
+
 =back
 
 =cut
-- 
2.39.5