Bug 29333: Fix encoding of imported UNIMARC authorities
[koha-ffzg.git] / t / db_dependent / ImportBatch.t
1 #!/usr/bin/perl
2
3 use Modern::Perl;
4 use Test::More tests => 19;
5 use utf8;
6 use File::Basename;
7 use File::Temp qw/tempfile/;
8
9 use t::lib::Mocks;
10 use t::lib::TestBuilder;
11
12 use Koha::Database;
13 use Koha::Import::Records;
14
15 BEGIN {
16     # Mock pluginsdir before loading Plugins module
17     my $path = dirname(__FILE__) . '/../lib/plugins';
18     t::lib::Mocks::mock_config( 'pluginsdir', $path );
19
20     use_ok('Koha::Plugins');
21     use_ok('C4::ImportBatch', qw( AddImportBatch GetImportBatch AddBiblioToBatch AddItemsToImportBiblio SetMatchedBiblionumber GetImportBiblios GetItemNumbersFromImportBatch CleanBatch DeleteBatch RecordsFromMarcPlugin ));
22 }
23
24 # Start transaction
25 my $schema  = Koha::Database->new->schema;
26 $schema->storage->txn_begin;
27 my $builder = t::lib::TestBuilder->new;
28 my $dbh = C4::Context->dbh;
29
30 # clear
31 $dbh->do('DELETE FROM import_batches');
32
33 my $sample_import_batch1 = {
34     matcher_id => 1,
35     template_id => 1,
36     branchcode => 'QRT',
37     overlay_action => 'create_new',
38     nomatch_action => 'create_new',
39     item_action => 'always_add',
40     import_status => 'staged',
41     batch_type => 'z3950',
42     file_name => 'test.mrc',
43     comments => 'test',
44     record_type => 'auth',
45 };
46
47 my $sample_import_batch2 = {
48     matcher_id => 2,
49     template_id => 2,
50     branchcode => 'QRZ',
51     overlay_action => 'create_new',
52     nomatch_action => 'create_new',
53     item_action => 'always_add',
54     import_status => 'staged',
55     batch_type => 'z3950',
56     file_name => 'test.mrc',
57     comments => 'test',
58     record_type => 'auth',
59 };
60
61 my $id_import_batch1 = C4::ImportBatch::AddImportBatch($sample_import_batch1);
62 my $id_import_batch2 = C4::ImportBatch::AddImportBatch($sample_import_batch2);
63
64 like( $id_import_batch1, '/^\d+$/', "AddImportBatch for sample_import_batch1 return an id" );
65 like( $id_import_batch2, '/^\d+$/', "AddImportBatch for sample_import_batch2 return an id" );
66
67 #Test GetImportBatch
68 my $importbatch2 = C4::ImportBatch::GetImportBatch( $id_import_batch2 );
69 delete $importbatch2->{upload_timestamp};
70 delete $importbatch2->{import_batch_id};
71 delete $importbatch2->{num_records};
72 delete $importbatch2->{num_items};
73 delete $importbatch2->{profile_id};
74 delete $importbatch2->{profile};
75
76 is_deeply( $importbatch2, $sample_import_batch2,
77     "GetImportBatch returns the right informations about $sample_import_batch2" );
78
79 my $importbatch1 = C4::ImportBatch::GetImportBatch( $id_import_batch1 );
80 delete $importbatch1->{upload_timestamp};
81 delete $importbatch1->{import_batch_id};
82 delete $importbatch1->{num_records};
83 delete $importbatch1->{num_items};
84 delete $importbatch1->{profile_id};
85 delete $importbatch1->{profile};
86
87 is_deeply( $importbatch1, $sample_import_batch1,
88     "GetImportBatch returns the right informations about $sample_import_batch1" );
89
90 my $record = MARC::Record->new;
91 # FIXME Create another MARC::Record which won't be modified
92 # AddItemsToImportBiblio will remove the items field from the record passed in parameter.
93 my $original_record = MARC::Record->new;
94 $record->leader('03174nam a2200445 a 4500');
95 $original_record->leader('03174nam a2200445 a 4500');
96 my ($item_tag, $item_subfield) = C4::Biblio::GetMarcFromKohaField( 'items.itemnumber' );
97 my @fields;
98 if (C4::Context->preference('marcflavour') eq 'UNIMARC') {
99     @fields = (
100         MARC::Field->new(
101             100, ' ', ' ',
102             a => '20220520d        u||y0frey50      ba',
103         ),
104         MARC::Field->new(
105             700, ' ', ' ',
106             a => 'Knuth, Donald Ervin',
107             f => '1938',
108         ),
109         MARC::Field->new(
110             200, ' ', ' ',
111             a => 'The art of computer programming',
112             f => 'Donald E. Knuth.',
113         ),
114         MARC::Field->new(
115             650, ' ', '0',
116             a => 'Computer programming.',
117             9 => '462',
118         ),
119         MARC::Field->new(
120             $item_tag, ' ', ' ',
121             e => 'my edition ❤',
122             i => 'my item part',
123         ),
124         MARC::Field->new(
125             $item_tag, ' ', ' ',
126             e => 'my edition 2',
127             i => 'my item part 2',
128         ),
129     );
130 } else {
131     @fields = (
132         MARC::Field->new(
133             100, '1', ' ',
134             a => 'Knuth, Donald Ervin',
135             d => '1938',
136         ),
137         MARC::Field->new(
138             245, '1', '4',
139             a => 'The art of computer programming',
140             c => 'Donald E. Knuth.',
141         ),
142         MARC::Field->new(
143             650, ' ', '0',
144             a => 'Computer programming.',
145             9 => '462',
146         ),
147         MARC::Field->new(
148             $item_tag, ' ', ' ',
149             e => 'my edition ❤',
150             i => 'my item part',
151         ),
152         MARC::Field->new(
153             $item_tag, ' ', ' ',
154             e => 'my edition 2',
155             i => 'my item part 2',
156         ),
157     );
158 }
159 $record->append_fields(@fields);
160 $original_record->append_fields(@fields);
161 my $import_record_id = AddBiblioToBatch( $id_import_batch1, 0, $record, 'utf8', int(rand(99999)), 0 );
162 AddItemsToImportBiblio( $id_import_batch1, $import_record_id, $record, 0 );
163
164 my $import_record = Koha::Import::Records->find($import_record_id);
165 my $record_from_import_biblio_with_items = $import_record->get_marc_record({ embed_items => 1 });
166 $original_record->leader($record_from_import_biblio_with_items->leader());
167 is_deeply( $record_from_import_biblio_with_items, $original_record, 'Koha::Import::Record::get_marc_record should return the record with items if specified' );
168 my $utf8_field = $record_from_import_biblio_with_items->subfield($item_tag, 'e');
169 is($utf8_field, 'my edition ❤');
170 $original_record->delete_fields($original_record->field($item_tag)); #Remove items fields
171 my $record_from_import_biblio_without_items = $import_record->get_marc_record();
172 $original_record->leader($record_from_import_biblio_without_items->leader());
173 is_deeply( $record_from_import_biblio_without_items, $original_record, 'Koha::Import::Record::get_marc_record should return the record without items by default' );
174
175 my $another_biblio = $builder->build_sample_biblio;
176 C4::ImportBatch::SetMatchedBiblionumber( $import_record_id, $another_biblio->biblionumber );
177 my $import_biblios = GetImportBiblios( $import_record_id );
178 is( $import_biblios->[0]->{matched_biblionumber}, $another_biblio->biblionumber, 'SetMatchedBiblionumber  should set the correct biblionumber' );
179
180 # Add a few tests for GetItemNumbersFromImportBatch
181 my @a = GetItemNumbersFromImportBatch( $id_import_batch1 );
182 is( @a, 0, 'No item numbers expected since we did not commit' );
183 my $itemno = $builder->build_sample_item->itemnumber;
184 # Link this item to the import item to fool GetItemNumbersFromImportBatch
185 my $sql = "UPDATE import_items SET itemnumber=? WHERE import_record_id=?";
186 $dbh->do( $sql, undef, $itemno, $import_record_id );
187 @a = GetItemNumbersFromImportBatch( $id_import_batch1 );
188 is( @a, 2, 'Expecting two items now' );
189 is( $a[0], $itemno, 'Check the first returned itemnumber' );
190 # Now delete the item and check again
191 $dbh->do( "DELETE FROM items WHERE itemnumber=?", undef, $itemno );
192 @a = GetItemNumbersFromImportBatch( $id_import_batch1 );
193 is( @a, 0, 'No item numbers expected since we deleted the item' );
194 $dbh->do( $sql, undef, undef, $import_record_id ); # remove link again
195
196 # fresh data
197 my $sample_import_batch3 = {
198     matcher_id => 3,
199     template_id => 3,
200     branchcode => 'QRT',
201     overlay_action => 'create_new',
202     nomatch_action => 'create_new',
203     item_action => 'always_add',
204     import_status => 'staged',
205     batch_type => 'z3950',
206     file_name => 'test.mrc',
207     comments => 'test',
208     record_type => 'auth',
209 };
210
211 my $id_import_batch3 = C4::ImportBatch::AddImportBatch($sample_import_batch3);
212
213 # Test CleanBatch
214 C4::ImportBatch::CleanBatch( $id_import_batch3 );
215 $import_record = get_import_record( $id_import_batch3 );
216 is( $import_record, "0E0", "Batch 3 has been cleaned" );
217
218 # Test DeleteBatch
219 C4::ImportBatch::DeleteBatch( $id_import_batch3 );
220 my $import_batch = C4::ImportBatch::GetImportBatch( $id_import_batch3 );
221 is( $import_batch, undef, "Batch 3 has been deleted");
222
223 subtest "_batchCommitItems" => sub {
224     plan tests => 3;
225
226     my $exist_item = $builder->build_sample_item;
227     my $import_item = $builder->build_object({ class => 'Koha::Import::Record::Items', value => {
228         marcxml => q{<?xml version="1.0" encoding="UTF-8"?>
229 <collection
230   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
231   xsi:schemaLocation="http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd"
232   xmlns="http://www.loc.gov/MARC21/slim">
233
234 <record>
235   <leader>00000    a              </leader>
236   <datafield tag="952" ind1=" " ind2=" ">
237     <subfield code="a">CPL</subfield>
238     <subfield code="b">CPL</subfield>
239     <subfield code="c">GEN</subfield>
240     <subfield code="p">}.$exist_item->barcode.q{</subfield>
241     <subfield code="y">BK</subfield>
242   </datafield>
243 </record>
244 </collection>
245         },
246     }});
247
248     my ( $num_items_added, $num_items_replaced, $num_items_errored ) =
249         C4::ImportBatch::_batchCommitItems( $import_item->import_record_id, 32, 'always_add',64 );
250     is( $num_items_errored, 1, "Item with duplicate barcode fails when action always_add" );
251     $import_item->discard_changes();
252     is( $import_item->status, 'error', "Import item marked as error when duplicate barcode and action always_add");
253     is( $import_item->import_error, 'duplicate item barcode', 'Error correctly set when import item has duplicate barcode and action always_add' );
254 };
255
256 subtest "RecordsFromMarcPlugin" => sub {
257     plan tests => 5;
258
259     # Create a test file
260     my ( $fh, $name ) = tempfile();
261     if (C4::Context->preference('marcflavour') eq 'UNIMARC') {
262         print $fh q{
263 003 = NLAmRIJ
264 100,a = 20220520d        u||y0frey50      ba
265 700,a = Author
266 200,ind2 = 0
267 200,a = Silence in the library
268 500 , a= Some note
269
270 700,a = Another
271 245,a = Noise in the library};
272         close $fh;
273     } else {
274         print $fh q|
275 003 = NLAmRIJ
276 100,a = Author
277 245,ind2 = 0
278 245,a = Silence in the library
279 500 , a= Some note
280
281 100,a = Another
282 245,a = Noise in the library|;
283         close $fh;
284     }
285
286     t::lib::Mocks::mock_config( 'enable_plugins', 1 );
287
288     my $plugins = Koha::Plugins->new;
289     $plugins->InstallPlugins;
290     my ($plugin) = $plugins->GetPlugins({ all => 1, metadata => { name => 'MarcFieldValues' } });
291     isnt( $plugin, undef, "Plugin found" );
292     my $records = C4::ImportBatch::RecordsFromMarcPlugin( $name, ref $plugin, 'UTF-8' );
293     is( @$records, 2, 'Two results returned' );
294     is( ref $records->[0], 'MARC::Record', 'Returned MARC::Record object' );
295     if (C4::Context->preference('marcflavour') eq 'UNIMARC') {
296         is( $records->[0]->subfield('200', 'a'), 'Silence in the library',
297             'Checked one field in first record' );
298         is( $records->[1]->subfield('700', 'a'), 'Another',
299             'Checked one field in second record' );
300     } else {
301         is( $records->[0]->subfield('245', 'a'), 'Silence in the library',
302             'Checked one field in first record' );
303         is( $records->[1]->subfield('100', 'a'), 'Another',
304             'Checked one field in second record' );
305     }
306 };
307
308 subtest "_get_commit_action" => sub {
309     plan tests => 24;
310     my $mock_import = Test::MockModule->new("C4::ImportBatch");
311
312     $mock_import->mock( GetBestRecordMatch => sub { return 5; } );
313     foreach my $record_type ( ('biblio','authority') ){
314         foreach my $match_action ( ('replace','create_new','ignore') ){
315             foreach my $no_match_action ( ('create_new','ignore') ){
316                 my ($result, $match, $item_result) =
317                     C4::ImportBatch::_get_commit_action($match_action, $no_match_action, 'always_add', 'auto_match', 42, $record_type);
318                 is( $result, $match_action, "When match found amd chosen we return the match_action for $record_type records with match action $match_action and no match action $no_match_action");
319             }
320         }
321     }
322
323     $mock_import->mock( GetBestRecordMatch => sub { my $matches = undef; return $matches; } );
324     foreach my $record_type ( ('biblio','authority') ){
325         foreach my $match_action ( ('replace','create_new','ignore') ){
326             foreach my $no_match_action ( ('create_new','ignore') ){
327                 my ($result, $match, $item_result) =
328                     C4::ImportBatch::_get_commit_action($match_action, $no_match_action, 'always_add', 'auto_match', 42, $record_type);
329                 is( $result, $no_match_action, "When no match found or chosen we return the match_action for $record_type records with match action $match_action and no match action $no_match_action");
330             }
331         }
332     }
333
334 };
335
336 sub get_import_record {
337     my $id_import_batch = shift;
338     return $dbh->do('SELECT * FROM import_records WHERE import_batch_id = ?', undef, $id_import_batch);
339 }
340
341 $schema->storage->txn_rollback;