From c8217516b1e446ebc614f7e015c9bf6a6cfcac89 Mon Sep 17 00:00:00 2001
From: Alex Arnaud <alex.arnaud@biblibre.com>
Date: Wed, 9 Dec 2015 11:09:58 +0100
Subject: [PATCH] Bug 15336 - New command-line script: merge_bookseller.pl
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Test plan (i.e. merge bookseller n° 3 into the n° 6):
run perl misc/migration_tools/merge_booksellers.pl -f 3 -t 6 -v -c
Check that basketgroups, baskets, contacts, contracts and invoices
had moved into bookseller 6.
Check that bookseller n° 3 has been deleted.
Remove -c (confirm) parameter to run in test mode only.
---
Koha/Acquisition/Bookseller.pm | 29 ++++++++
misc/migration_tools/merge_vendors.pl | 120 ++++++++++++++++++++++++++++++++++
t/Bookseller.t | 99 +++++++++++++++++++++++++++-
t/db_dependent/Bookseller.t | 105 ++++++++++++++++++++++++++++-
4 files changed, 349 insertions(+), 4 deletions(-)
create mode 100644 misc/migration_tools/merge_vendors.pl
diff --git a/Koha/Acquisition/Bookseller.pm b/Koha/Acquisition/Bookseller.pm
index e32b010..d19df66 100644
--- a/Koha/Acquisition/Bookseller.pm
+++ b/Koha/Acquisition/Bookseller.pm
@@ -26,6 +26,35 @@ sub subscriptions {
return Koha::Subscriptions->search( { aqbooksellerid => $self->id } );
}
+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;
+}
+
+# TODO Move code from ModBookseller
+sub update {
+ die "not implemented yet";
+}
+
sub _type {
return 'Aqbookseller';
}
diff --git a/misc/migration_tools/merge_vendors.pl b/misc/migration_tools/merge_vendors.pl
new file mode 100644
index 0000000..1471c74
--- /dev/null
+++ b/misc/migration_tools/merge_vendors.pl
@@ -0,0 +1,120 @@
+#!/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 <http://www.gnu.org/licenses>.
+
+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)
+
+=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 recommanded to run without
+ --confirm first to be sure of the changes.
+
+=item B<--from>
+
+ --from=<vendorid> The source vendor identifier that will be merged in
+ target vendor.
+
+=item B<--to>
+
+ --to=<vendorid> The target vendor identifier in which merge
+ source vendor.
+
+=back
+
+=cut
diff --git a/t/Bookseller.t b/t/Bookseller.t
index 360a0ad..6d6aab3 100755
--- a/t/Bookseller.t
+++ b/t/Bookseller.t
@@ -1,14 +1,107 @@
#!/usr/bin/perl
#
-# This Koha test module is a stub!
+# This Koha test module is a stub!
# Add more tests here!!!
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::Bookseller->fetch({id => $booksellerid1});
+
+my ($error, $result) = $bookseller->merge_to(345876876);
+is($error, "Unknown target bookseller number: 345876876", 'Merge to unknown bookseller return an error' );
+
+($error, $result) = $bookseller->merge_to($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(C4::Bookseller::Contact->fetch($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 77cf3ef..f96e35b 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;
@@ -11,9 +11,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::Order;
@@ -38,6 +41,8 @@ $schema->storage->txn_begin();
$dbh->{RaiseError} = 1;
+our $builder = t::lib::TestBuilder->new;
+
#Start tests
$dbh->do(q|DELETE FROM aqorders|);
$dbh->do(q|DELETE FROM aqbasket|);
@@ -751,6 +756,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();
@@ -774,3 +864,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.7.4