From bf7bd51b054478719327910787f70993fde8f869 Mon Sep 17 00:00:00 2001 From: Alex Arnaud Date: Wed, 9 Dec 2015 11:09:58 +0100 Subject: [PATCH] Bug 15336: Add new command-line script: misc/migration_tools/merge_vendors.pl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test plan (i.e. merge bookseller n° 3with the n° 6): run perl misc/migration_tools/merge_vendors.pl -f 3 -t 6 -v -c Check that basketgroups, baskets, contacts, contracts, invoices, deleteditems, items and subscriptions had moved into bookseller 6. Check that bookseller n° 3 has been deleted. Remove -c (confirm) parameter to run in test mode only. Signed-off-by: Marc Véron Signed-off-by: Katrin Fischer --- Koha/Acquisition/Bookseller.pm | 33 ++++++++++ misc/migration_tools/merge_vendors.pl | 121 ++++++++++++++++++++++++++++++++++ t/Bookseller.t | 113 +++++++++++++++++++++++++++++-- t/db_dependent/Bookseller.t | 105 ++++++++++++++++++++++++++++- 4 files changed, 366 insertions(+), 6 deletions(-) create mode 100755 misc/migration_tools/merge_vendors.pl diff --git a/Koha/Acquisition/Bookseller.pm b/Koha/Acquisition/Bookseller.pm index f2f08db109..283c654642 100644 --- a/Koha/Acquisition/Bookseller.pm +++ b/Koha/Acquisition/Bookseller.pm @@ -73,6 +73,39 @@ sub subscriptions { return Koha::Subscriptions->search( { aqbooksellerid => $self->id } ); } +=head3 merge_with + + my $from_vendor = Koha::Acquisition::Booksellers->find( $mergefrom ); + my $result = $from_vendor->merge_with($mergeto); + +merge source vendor (-f) with target vendor (-t) + +=cut + +sub merge_with { + my ($self, $booksellerid) = @_; + + my $result = {}; + + unless ( Koha::Acquisition::Booksellers->find( $booksellerid ) ) { + die("Unknown target bookseller number: $booksellerid"); + } + + foreach my $entity (qw(Aqbasketgroup Aqbasket Aqcontract Aqcontact Aqinvoice Deleteditem Item Subscription)) { + my $rs = Koha::Database->new()->schema->resultset($entity); + + my $foreign_key = $entity eq 'Subscription' ? 'aqbooksellerid' : 'booksellerid'; + $rs = $rs->search({$foreign_key => $self->id }); + + while (my $e = $rs->next) { + $e->set_column($foreign_key, $booksellerid); + $e->update(); + push @{ $result->{$entity} }, $e->id(); + } + } + return $result; +} + =head2 Internal methods =head3 _type diff --git a/misc/migration_tools/merge_vendors.pl b/misc/migration_tools/merge_vendors.pl new file mode 100755 index 0000000000..cc1c077fc6 --- /dev/null +++ b/misc/migration_tools/merge_vendors.pl @@ -0,0 +1,121 @@ +#!/usr/bin/perl + +# Copyright 2015 BibLibre +# +# 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 Koha::Acquisition::Bookseller; +use C4::Acquisition; +use C4::Contract; + +use Getopt::Long; +use Pod::Usage; + +my ($help, $verbose, $mergefrom, $mergeto, $confirm); +GetOptions( + 'help|h' => \$help, + 'verbose|v' => \$verbose, + 'from|f:s' => \$mergefrom, + 'to|t:s' => \$mergeto, + 'confirm|c' => \$confirm, +) || pod2usage(1); + +if ($help || !$mergefrom || !$mergeto) { + pod2usage(1); +} + +if ($mergefrom eq $mergeto) { + pod2usage('Source and target vendors should be different.'); +} + +my $schema = Koha::Database->schema; +$schema->storage->txn_begin; + +my $from_vendor = Koha::Acquisition::Booksellers->find( $mergefrom ); +die "Unknown vendor id ($mergefrom)" unless $from_vendor; + +my $report = $from_vendor->merge_with($mergeto); + +if ($confirm) { + $schema->storage->txn_commit; +} +else { + $schema->storage->txn_rollback; +} + +Koha::Acquisition::Booksellers->find($mergefrom)->delete if $confirm; + +if ($verbose) { + print_report($report); +} + +print "Nothing done (test only). Use confirm option to commit changes in database\n" unless $confirm; + +sub print_report { + my $report = shift; + + foreach my $entity (keys %$report) { + my $count = scalar @{ $report->{$entity} }; + my $ids = join(', ', @{ $report->{$entity} }); + print "$entity merged: $count (numbers: $ids)\n"; + } +} + + +=head1 NAME + +merge source vendor (-f) into target vendor (-t) - Move all related entities +in the target vendor: baskets and basket groups, contracts, contacts, invoices, items and subscriptions. + +=head1 SYNOPSIS + +** WARNING ** This script can delete data. You must only use it if you know what your are doing + +merge_vendors.pl [-h|--help] [-v|--verbose] [-c|--confirm] --from=vendorid --to=vendorid + +=head1 OPTIONS + +=over + +=item B<-h|--help> + +Print a brief help message. + +=item B<--verbose> + + --verbose Show more information on what is done. + +=item B<--confirm> + + --confirm Commit the changes in database. Running without this + parameter is like testing. It is recommended to run without + --confirm first to be sure of the changes. + +=item B<--from> + + --from= The identifier of the source vendor that will be merged with + the target vendor. + +=item B<--to> + + --to= The identifier of the target vendor that the source vendor + is merged with. + +=back + +=cut diff --git a/t/Bookseller.t b/t/Bookseller.t index 360a0ad444..aeaa4cae87 100755 --- a/t/Bookseller.t +++ b/t/Bookseller.t @@ -1,14 +1,119 @@ #!/usr/bin/perl + +# 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. # -# This Koha test module is a stub! -# Add more tests here!!! +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . use strict; use warnings; -use Test::More tests => 1; +use C4::Acquisition qw( GetBasketgroup GetBasket GetInvoice ); +use C4::Contract qw( GetContract ); +use C4::Items qw ( GetItem ); +use C4::Serials qw( GetSubscription ); +use t::lib::TestBuilder; + +use Test::More tests => 14; BEGIN { - use_ok('C4::Bookseller'); + use_ok('Koha::Acquisition::Bookseller'); +} + +my $schema = Koha::Database->schema; +$schema->storage->txn_begin; + +our $builder = t::lib::TestBuilder->new; + +my $bookseller1 = create('Aqbookseller'); +my $booksellerid1 = $bookseller1->{id}; +my $bookseller2 = create('Aqbookseller'); +my $booksellerid2 = $bookseller2->{id}; + +my $bg1 = create('Aqbasketgroup', $booksellerid1); +my $bg2 = create('Aqbasketgroup', $booksellerid1); +my $bg3 = create('Aqbasketgroup', $booksellerid2); + +my $basket1 = create('Aqbasket', $booksellerid1); +my $basket2 = create('Aqbasket', $booksellerid1); + +my $contract = create('Aqcontract', $booksellerid1); + +my $contact = create('Aqcontact', $booksellerid1); + +my $invoice = create('Aqinvoice', $booksellerid1); + +my $deleteditem = create('Deleteditem', $booksellerid1); + +my $item1 = create('Item', $booksellerid1); + +my $subscription = create('Subscription', $booksellerid1); + +my $bookseller = Koha::Acquisition::Booksellers->find( $booksellerid1 ); + +my $result = eval{ $bookseller->merge_with(345876876); }; +like($@, qr/Unknown target bookseller number: 345876876/, 'Merge with unknown bookseller should die.'); + +$result = $bookseller->merge_with($booksellerid2); +my $expected_result = { + Aqbasketgroup => [$bg1->{id}, $bg2->{id}], + Aqbasket => [$basket1->{basketno}, $basket2->{basketno}], + Aqcontract => [$contract->{contractnumber}], + Aqcontact => [$contact->{id}], + Aqinvoice => [$invoice->{invoiceid}], + Deleteditem => [$deleteditem->{itemnumber}], + Item => [$item1->{itemnumber}], + Subscription => [$subscription->{subscriptionid}] +}; + +is_deeply($result, $expected_result, 'Result should be as expected'); + +is(GetBasketgroup($bg1->{id})->{'booksellerid'}, $booksellerid2, 'Basket group 1 has bookseller 2'); + +is(GetBasketgroup($bg2->{id})->{'booksellerid'}, $booksellerid2, 'Basket group 2 has bookseller 2'); + +is(GetBasketgroup($bg3->{id})->{'booksellerid'}, $booksellerid2, 'Basket group 3 keep bookseller 2'); + +is(GetBasket($basket1->{basketno})->{'booksellerid'}, $booksellerid2, 'Basket 1 has bookseller 2'); + +is(GetBasket($basket2->{basketno})->{'booksellerid'}, $booksellerid2, 'Basket 2 has bookseller 2'); + +is(GetContract({contractnumber => $contract->{contractnumber}})->{'booksellerid'}, $booksellerid2, 'Basket 1 has bookseller 2'); + +is(Koha::Acquisition::Bookseller::Contacts->find( $contact->{id} )->booksellerid, $booksellerid2, 'Contact 1 has booksellerid 2'); + +is(GetInvoice($invoice->{invoiceid})->{'booksellerid'}, $booksellerid2, 'Invoice has bookseller 2'); + +my $item = Koha::Database->new()->schema->resultset('Deleteditem') + ->find({itemnumber => $deleteditem->{itemnumber}}); +is($item->get_column('booksellerid'), $booksellerid2, 'Deleted item has bookseller 2'); + +is(GetItem($item1->{itemnumber})->{'booksellerid'}, $booksellerid2, 'Item has bookseller 2'); + +is(GetSubscription($subscription->{subscriptionid})->{'aqbooksellerid'}, $booksellerid2, 'Subscription has bookseller 2'); + +$schema->storage->txn_rollback; + +sub create { + my ($source, $booksellerid) = @_; + + my $build = { source => $source}; + my $foreign_key = $source eq 'Subscription' ? 'aqbooksellerid' : 'booksellerid'; + $build->{value} = {$foreign_key => $booksellerid} if $booksellerid; + + my $entity = $builder->build($build); + + return $entity; } +1; diff --git a/t/db_dependent/Bookseller.t b/t/db_dependent/Bookseller.t index b9de02cf9c..3ca652f1ef 100644 --- a/t/db_dependent/Bookseller.t +++ b/t/db_dependent/Bookseller.t @@ -2,7 +2,7 @@ use Modern::Perl; -use Test::More tests => 86; +use Test::More tests => 99; use Test::MockModule; use Test::Warn; @@ -13,9 +13,12 @@ use Koha::DateUtils; use DateTime::Duration; use t::lib::Mocks; use C4::Acquisition; +use C4::Contract qw( GetContract ); +use C4::Items qw ( GetItem ); use C4::Serials; use C4::Budgets; use C4::Biblio; +use t::lib::TestBuilder; use Koha::Acquisition::Booksellers; use Koha::Acquisition::Orders; @@ -38,7 +41,7 @@ my $database = Koha::Database->new(); my $schema = $database->schema(); $schema->storage->txn_begin(); $dbh->{RaiseError} = 1; -my $builder = t::lib::TestBuilder->new; +our $builder = t::lib::TestBuilder->new; #Start tests $dbh->do(q|DELETE FROM aqorders|); @@ -757,6 +760,91 @@ is( $first_contact->phone, is( $contacts->count, 1, 'Only one contact after modification' ); +my $bookseller1 = create('Aqbookseller'); +my $booksellerid1 = $bookseller1->{id}; +my $bookseller2 = create('Aqbookseller'); +my $booksellerid2 = $bookseller2->{id}; + +my $bg1 = create( 'Aqbasketgroup', $booksellerid1 ); +my $bg2 = create( 'Aqbasketgroup', $booksellerid1 ); +my $bg3 = create( 'Aqbasketgroup', $booksellerid2 ); + +my $basket1 = create( 'Aqbasket', $booksellerid1 ); +my $basket2 = create( 'Aqbasket', $booksellerid1 ); + +my $contract = create( 'Aqcontract', $booksellerid1 ); + +my $contact = create( 'Aqcontact', $booksellerid1 ); + +my $invoice = create( 'Aqinvoice', $booksellerid1 ); + +my $deleteditem = create( 'Deleteditem', $booksellerid1 ); + +my $item1 = create( 'Item', $booksellerid1 ); + +my $subscription = create( 'Subscription', $booksellerid1 ); + +$bookseller = Koha::Acquisition::Booksellers->find( $booksellerid1 ); + +my $result = eval { $bookseller->merge_with(345876876) }; +ok( + $@ =~ /^Unknown target bookseller number: 345876876/, + 'Merge to unknown bookseller return an error' +); + +$result = $bookseller->merge_with($booksellerid2); +my $expected_result = { + Aqbasketgroup => [ $bg1->{id}, $bg2->{id} ], + Aqbasket => [ $basket1->{basketno}, $basket2->{basketno} ], + Aqcontract => [ $contract->{contractnumber} ], + Aqcontact => [ $contact->{id} ], + Aqinvoice => [ $invoice->{invoiceid} ], + Deleteditem => [ $deleteditem->{itemnumber} ], + Item => [ $item1->{itemnumber} ], + Subscription => [ $subscription->{subscriptionid} ] +}; + +is_deeply( $result, $expected_result, 'Result should be as expected' ); + +is( GetBasketgroup( $bg1->{id} )->{'booksellerid'}, + $booksellerid2, 'Basket group 1 has bookseller 2' ); + +is( GetBasketgroup( $bg2->{id} )->{'booksellerid'}, + $booksellerid2, 'Basket group 2 has bookseller 2' ); + +is( GetBasketgroup( $bg3->{id} )->{'booksellerid'}, + $booksellerid2, 'Basket group 3 keep bookseller 2' ); + +is( GetBasket( $basket1->{basketno} )->{'booksellerid'}, + $booksellerid2, 'Basket 1 has bookseller 2' ); + +is( GetBasket( $basket2->{basketno} )->{'booksellerid'}, + $booksellerid2, 'Basket 2 has bookseller 2' ); + +is( + GetContract( { contractnumber => $contract->{contractnumber} } ) + ->{'booksellerid'}, + $booksellerid2, + 'Basket 1 has bookseller 2' +); + +is( Koha::Acquisition::Bookseller::Contacts->find( $contact->{id} )->booksellerid, + $booksellerid2, 'Contact 1 has booksellerid 2' ); + +is( GetInvoice( $invoice->{invoiceid} )->{'booksellerid'}, + $booksellerid2, 'Invoice has bookseller 2' ); + +my $item = Koha::Database->new()->schema->resultset('Deleteditem') + ->find( { itemnumber => $deleteditem->{itemnumber} } ); +is( $item->get_column('booksellerid'), + $booksellerid2, 'Deleted item has bookseller 2' ); + +is( GetItem( $item1->{itemnumber} )->{'booksellerid'}, + $booksellerid2, 'Item has bookseller 2' ); + +is( GetSubscription( $subscription->{subscriptionid} )->{'aqbooksellerid'}, + $booksellerid2, 'Subscription has bookseller 2' ); + #End transaction $schema->storage->txn_rollback(); @@ -780,3 +868,16 @@ sub field_filter { } return $struct; } + +sub create { + my ( $source, $booksellerid ) = @_; + + my $build = { source => $source }; + my $foreign_key = + $source eq 'Subscription' ? 'aqbooksellerid' : 'booksellerid'; + $build->{value} = { $foreign_key => $booksellerid } if $booksellerid; + + my $entity = $builder->build($build); + + return $entity; +} -- 2.14.1