Bug 26481: Add Koha::Item::Transfer->in_transit method
[koha.git] / t / db_dependent / Serials.t
1 #!/usr/bin/perl
2 #
3 # This Koha test module is a stub!
4 # Add more tests here!!!
5
6 use Modern::Perl;
7
8 use C4::Serials;
9 use C4::Serials::Frequency;
10 use C4::Serials::Numberpattern;
11 use C4::Debug;
12 use C4::Biblio;
13 use C4::Budgets;
14 use C4::Items;
15 use Koha::Database;
16 use Koha::DateUtils;
17 use Koha::Acquisition::Booksellers;
18 use t::lib::Mocks;
19 use t::lib::TestBuilder;
20 use Test::More tests => 49;
21
22 BEGIN {
23     use_ok('C4::Serials');
24 }
25
26 my $schema = Koha::Database->new->schema;
27 $schema->storage->txn_begin;
28 my $dbh = C4::Context->dbh;
29
30 my $builder = t::lib::TestBuilder->new();
31
32 # This could/should be used for all untested methods
33 my @methods = ('updateClaim');
34 can_ok('C4::Serials', @methods);
35
36 $dbh->do(q|UPDATE marc_subfield_structure SET value_builder="callnumber.pl" where kohafield="items.itemcallnumber" and frameworkcode=''|);
37
38 my $bookseller = Koha::Acquisition::Bookseller->new(
39     {
40         name => "my vendor",
41         address1 => "bookseller's address",
42         phone => "0123456",
43         active => 1
44     }
45 );
46
47 my ($biblionumber, $biblioitemnumber) = AddBiblio(MARC::Record->new, '');
48
49 my $bpid = AddBudgetPeriod({
50     budget_period_startdate   => '2015-01-01',
51     budget_period_enddate     => '2015-12-31',
52     budget_period_description => "budget desc"
53 });
54
55 my $budget_id = AddBudget({
56     budget_code        => "ABCD",
57     budget_amount      => "123.132",
58     budget_name        => "Périodiques",
59     budget_notes       => "This is a note",
60     budget_period_id   => $bpid
61 });
62
63 my $frequency_id = AddSubscriptionFrequency({ description => "Test frequency 1" });
64 my $pattern_id = AddSubscriptionNumberpattern({
65     label => 'Test numberpattern 1',
66     description => 'Description for numberpattern 1',
67     numberingmethod => '{X}',
68     label1 => q{},
69     add1 => 1,
70     every1 => 1,
71     every1 => 1,
72     numbering1 => 1,
73     whenmorethan1 => 1,
74 });
75
76 my $notes = "a\nnote\non\nseveral\nlines";
77 my $internalnotes = 'intnotes';
78 my $subscriptionid = NewSubscription(
79     undef,      "",     undef, undef, $budget_id, $biblionumber,
80     '2013-01-01', $frequency_id, undef, undef,  undef,
81     undef,      undef,  undef, undef, undef, undef,
82     1,          $notes, ,undef, '2013-01-01', undef, $pattern_id,
83     undef,       undef,  0,    $internalnotes,  0,
84     undef, undef, 0,          undef,         '2013-12-31', 0
85 );
86
87 my $subscriptioninformation = GetSubscription( $subscriptionid );
88
89 is( $subscriptioninformation->{notes}, $notes, 'NewSubscription should set notes' );
90 is( $subscriptioninformation->{internalnotes}, $internalnotes, 'NewSubscription should set internalnotes' );
91
92 my $subscription_history = C4::Serials::GetSubscriptionHistoryFromSubscriptionId($subscriptionid);
93 is( $subscription_history->{opacnote}, undef, 'NewSubscription should not set subscriptionhistory opacnotes' );
94 is( $subscription_history->{librariannote}, undef, 'NewSubscription should not set subscriptionhistory librariannotes' );
95
96 my @subscriptions = SearchSubscriptions({string => $subscriptioninformation->{bibliotitle}, orderby => 'title' });
97 isa_ok( \@subscriptions, 'ARRAY' );
98
99 @subscriptions = SearchSubscriptions({ issn => $subscriptioninformation->{issn}, orderby => 'title' });
100 isa_ok( \@subscriptions, 'ARRAY' );
101
102 @subscriptions = SearchSubscriptions({ ean => $subscriptioninformation->{ean}, orderby => 'title' });
103 isa_ok( \@subscriptions, 'ARRAY' );
104
105 @subscriptions = SearchSubscriptions({ biblionumber => $subscriptioninformation->{bibnum}, orderby => 'title' });
106 isa_ok( \@subscriptions, 'ARRAY' );
107
108 my $frequency = GetSubscriptionFrequency($subscriptioninformation->{periodicity});
109 my $old_frequency;
110 if (not $frequency->{unit}) {
111     $old_frequency = $frequency->{id};
112     $frequency->{unit} = "month";
113     $frequency->{unitsperissue} = 1;
114     $frequency->{issuesperunit} = 1;
115     $frequency->{description} = "Frequency created by t/db_dependant/Serials.t";
116     $subscriptioninformation->{periodicity} = AddSubscriptionFrequency($frequency);
117     $subscriptioninformation->{serialsadditems} = 1;
118
119     ModSubscription( @$subscriptioninformation{qw(
120         librarian branchcode aqbooksellerid cost aqbudgetid startdate
121         periodicity firstacquidate irregularity numberpattern locale
122         numberlength weeklength monthlength lastvalue1 innerloop1 lastvalue2
123         innerloop2 lastvalue3 innerloop3 status biblionumber callnumber notes
124         letter manualhistory internalnotes serialsadditems staffdisplaycount
125         opacdisplaycount graceperiod location enddate subscriptionid
126         skip_serialseq
127     )} );
128 }
129 my $expirationdate = GetExpirationDate($subscriptionid) ;
130 ok( $expirationdate, "expiration date is not NULL" );
131
132 ok(C4::Serials::GetSubscriptionHistoryFromSubscriptionId($subscriptionid), 'test getting history from sub-scription');
133
134 my ($serials_count, @serials) = GetSerials($subscriptionid);
135 ok($serials_count > 0, 'Subscription has at least one serial');
136 my $serial = $serials[0];
137
138 isa_ok(C4::Serials::GetSerialInformation($serial->{serialid}), 'HASH', 'test getting Serial Information');
139
140 subtest 'Values should not be erased on editing' => sub {
141
142     plan tests => 1;
143
144     my $biblio = $builder->build_sample_biblio();
145     my $biblionumber = $biblio->biblionumber;
146     my ( $icn_tag, $icn_sf ) = GetMarcFromKohaField( 'items.itemcallnumber' );
147     my ( $it_tag, $it_sf )   = GetMarcFromKohaField( 'items.itype' );
148
149     my $itemtype = $builder->build( { source => 'Itemtype' } )->{itemtype};
150     my $itemcallnumber = 'XXXmy itemcallnumberXXX';
151
152     my $item_record    = MARC::Record->new;
153
154     $item_record->append_fields(
155         MARC::Field->new( '080', '', '', "a" => "default" ),
156         MARC::Field->new(
157             $icn_tag, '', '',
158             $icn_sf => $itemcallnumber,
159             $it_sf  => $itemtype
160         )
161     );
162     my ( undef, undef, $itemnumber ) = C4::Items::AddItemFromMarc( $item_record, $biblionumber );
163     my $serialid = C4::Serials::NewIssue( "serialseq", $subscriptionid, $biblionumber,
164                                           1, undef, undef, "publisheddatetext", "notes", "routingnotes" );
165     C4::Serials::AddItem2Serial( $serialid, $itemnumber );
166     my $serial_info = C4::Serials::GetSerialInformation($serialid);
167     my ($itemcallnumber_info) = grep { $_->{kohafield} eq 'items.itemcallnumber' }
168                                      @{ $serial_info->{items}[0]->{iteminformation} };
169     like( $itemcallnumber_info->{marc_value}, qr|value="$itemcallnumber"| );
170 };
171
172 # Delete created frequency
173 if ($old_frequency) {
174     my $freq_to_delete = $subscriptioninformation->{periodicity};
175     $subscriptioninformation->{periodicity} = $old_frequency;
176
177     ModSubscription( @$subscriptioninformation{qw(
178         librarian branchcode aqbooksellerid cost aqbudgetid startdate
179         periodicity firstacquidate irregularity numberpattern locale
180         numberlength weeklength monthlength lastvalue1 innerloop1 lastvalue2
181         innerloop2 lastvalue3 innerloop3 status biblionumber callnumber notes
182         letter manualhistory internalnotes serialsadditems staffdisplaycount
183         opacdisplaycount graceperiod location enddate subscriptionid
184         skip_serialseq
185     )} );
186
187     DelSubscriptionFrequency($freq_to_delete);
188 }
189
190 # Test calling subs without parameters
191 is(C4::Serials::AddItem2Serial(), undef, 'test adding item to serial');
192 is(C4::Serials::GetFullSubscription(), undef, 'test getting full subscription');
193 is(C4::Serials::PrepareSerialsData(), undef, 'test preparing serial data');
194
195 subtest 'GetSubscriptionsFromBiblionumber' => sub {
196     plan tests => 4;
197
198     is( C4::Serials::GetSubscriptionsFromBiblionumber(),
199         undef, 'test getting subscriptions form biblio number' );
200
201     my $subscriptions = C4::Serials::GetSubscriptionsFromBiblionumber($biblionumber);
202     ModSubscriptionHistory( $subscriptions->[0]->{subscriptionid},
203         undef, undef, $notes, $notes, $notes );
204
205     $subscriptions = C4::Serials::GetSubscriptionsFromBiblionumber($biblionumber);
206     is( $subscriptions->[0]->{opacnote}, $notes,
207         'GetSubscriptionsFromBiblionumber should have returned the opacnote as it is in DB, ie. without br tags'
208     );
209     is( $subscriptions->[0]->{recievedlist}, $notes,
210         'GetSubscriptionsFromBiblionumber should have returned recievedlist as it is in DB, ie. without br tags'
211     );
212     is( $subscriptions->[0]->{missinglist}, $notes,
213         'GetSubscriptionsFromBiblionumber should have returned missinglist as it is in DB, ie. without br tags'
214     );
215 };
216
217 is(C4::Serials::GetSerials(), undef, 'test getting serials when you enter nothing');
218 is(C4::Serials::GetSerials2(), undef, 'test getting serials when you enter nothing');
219
220 is(C4::Serials::GetLatestSerials(), undef, 'test getting lastest serials');
221
222 is(C4::Serials::GetNextSeq(), undef, 'test getting next seq when you enter nothing');
223
224 is(C4::Serials::GetSeq(), undef, 'test getting seq when you enter nothing');
225
226 is(C4::Serials::CountSubscriptionFromBiblionumber(), undef, 'test counting subscription when nothing is entered');
227
228 is(C4::Serials::ModSubscriptionHistory(), undef, 'test modding subscription history');
229
230 is(C4::Serials::ModSerialStatus(),undef, 'test modding serials');
231
232 is(C4::Serials::findSerialsByStatus(), 0, 'test finding serial by status with no parameters');
233
234 is(C4::Serials::NewIssue(), undef, 'test getting 0 when nothing is entered');
235
236 is(C4::Serials::HasSubscriptionStrictlyExpired(), undef, 'test if the subscriptions has expired');
237 is(C4::Serials::HasSubscriptionExpired(), undef, 'test if the subscriptions has expired');
238
239 is(C4::Serials::GetLateOrMissingIssues(), undef, 'test getting last or missing issues');
240
241 subtest 'test_updateClaim' => sub {
242     plan tests => 11;
243
244     my $today = output_pref({ dt => dt_from_string, dateonly => 1 });
245     # Given ... nothing much
246     # When ... Then ...
247     my $result_0 = C4::Serials::updateClaim(undef);
248     is($result_0, undef, 'Got the expected undef from update claim with nothin');
249
250     # Given ... 3 serial. 2 of them updated.
251     my $claimdate_1   = dt_from_string('2001-01-13'); # arbitrary date some time in the past.
252     my $claim_count_1 = 5;
253     my $biblio = $builder->build_sample_biblio;
254     my $serial1 = $builder->build_object(
255         {
256             class => 'Koha::Serials',
257             value => {
258                 serialseq      => 'serialseq',
259                 subscriptionid => $subscriptionid,
260                 status         => 3,
261                 biblionumber   => $biblio->biblionumber,
262                 claimdate      => $claimdate_1,
263                 claims_count   => $claim_count_1,
264             }
265         }
266     );
267     my $serial2 = $builder->build_object(
268         {
269             class => 'Koha::Serials',
270             value => {
271                 serialseq      => 'serialseq',
272                 subscriptionid => $subscriptionid,
273                 status         => 3,
274                 biblionumber   => $biblio->biblionumber,
275                 claimdate      => $claimdate_1,
276                 claims_count   => $claim_count_1,
277             }
278         }
279     );
280     my $serial3 = $builder->build_object(
281         {
282             class => 'Koha::Serials',
283             value => {
284                 serialseq      => 'serialseq',
285                 subscriptionid => $subscriptionid,
286                 status         => 3,
287                 biblionumber   => $biblio->biblionumber,
288                 claimdate      => $claimdate_1,
289                 claims_count   => $claim_count_1,
290             }
291         }
292     );
293
294     # When ...
295     my $result_1 = C4::Serials::updateClaim([$serial1->serialid, $serial2->serialid]);
296
297     # Then ...
298     is($result_1, 2, 'Got the expected 2 from update claim with 2 serial ids');
299
300     my @late_or_missing_issues_1_0 = C4::Serials::GetLateOrMissingIssues(undef, $serial1->serialid);
301     is($late_or_missing_issues_1_0[0]->{claimdate}, $today, 'Got the expected first different claim date from update claim');
302     is($late_or_missing_issues_1_0[0]->{claims_count}, $claim_count_1+1, 'Got the expected first claim count from update claim');
303     is($late_or_missing_issues_1_0[0]->{status}, 7, 'Got the expected first claim status from update claim');
304
305     my @late_or_missing_issues_1_1 = C4::Serials::GetLateOrMissingIssues(undef, $serial2->serialid);
306     is($late_or_missing_issues_1_1[0]->{claimdate}, $today, 'Got the expected second different claim date from update claim');
307     is($late_or_missing_issues_1_1[0]->{claims_count}, $claim_count_1+1, 'Got the expected second claim count from update claim');
308     is($late_or_missing_issues_1_1[0]->{status}, 7, 'Got the expected second claim status from update claim');
309
310     my @late_or_missing_issues_1_2 = C4::Serials::GetLateOrMissingIssues(undef, $serial3->serialid);
311     is($late_or_missing_issues_1_2[0]->{claimdate}, output_pref({ dt => $claimdate_1, dateonly => 1}), 'Got the expected unchanged claim date from update claim');
312     is($late_or_missing_issues_1_2[0]->{claims_count}, $claim_count_1, 'Got the expected unchanged claim count from update claim');
313     is($late_or_missing_issues_1_2[0]->{status}, 3, 'Got the expected unchanged claim status from update claim');
314 };
315
316 is(C4::Serials::check_routing(), undef, 'test checking route');
317 is(C4::Serials::check_routing($subscriptionid), 0, 'There should not have any routing list for the subscription');
318 # TODO really test this check_routing subroutine
319
320 is(C4::Serials::addroutingmember(),undef, 'test adding route member');
321
322
323 # Unit tests for statuses management (Bug 11689)
324 $subscriptionid = NewSubscription(
325     undef,      "",     undef, undef, $budget_id, $biblionumber,
326     '2013-01-01', $frequency_id, undef, undef,  undef,
327     undef,      undef,  undef, undef, undef, undef,
328     1,          $notes,undef, '2013-01-01', undef, $pattern_id,
329     undef,       undef,  0,    $internalnotes,  0,
330     undef, undef, 0,          undef,         '2013-12-31', 0
331 );
332 my $total_issues;
333 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid );
334 is( $total_issues, 1, "NewSubscription created a first serial" );
335 is( @serials, 1, "GetSerials returns the serial" );
336 my $subscription = C4::Serials::GetSubscription($subscriptionid);
337 my $pattern = C4::Serials::Numberpattern::GetSubscriptionNumberpattern($subscription->{numberpattern});
338 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid );
339 my $publisheddate = output_pref({ dt => dt_from_string, dateformat => 'iso', dateonly => 1 });
340 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid );
341 $frequency = C4::Serials::Frequency::GetSubscriptionFrequency($subscription->{periodicity});
342 my $nextpublisheddate = C4::Serials::GetNextDate($subscription, $publisheddate, $frequency, 1);
343 my @statuses = qw( 2 2 3 3 3 3 3 4 4 41 42 43 44 5 );
344 # Add 14 serials
345 my $counter = 0;
346 for my $status ( @statuses ) {
347     my $serialseq = "No.".$counter;
348     my ( $expected_serial ) = GetSerials2( $subscriptionid, [1] );
349     C4::Serials::ModSerialStatus( $expected_serial->{serialid}, $serialseq, $publisheddate, $publisheddate, $publisheddate, $statuses[$counter], 'an useless note' );
350     $counter++;
351 }
352 # Here we have 15 serials with statuses : 2*2 + 5*3 + 2*4 + 1*41 + 1*42 + 1*43 + 1*44 + 1*5 + 1*1
353 my @serialsByStatus = C4::Serials::findSerialsByStatus(2,$subscriptionid);
354 is(@serialsByStatus,2,"findSerialsByStatus returns all serials with chosen status");
355 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid );
356 is( $total_issues, @statuses + 1, "GetSerials returns total_issues" );
357 my @arrived_missing = map { my $status = $_->{status}; ( grep { /^$status$/ } qw( 2 4 41 42 43 44 5 ) ) ? $_ : () } @serials;
358 my @others = map { my $status = $_->{status}; ( grep { /^$status$/ } qw( 2 4 41 42 43 44 5 ) ) ? () : $_ } @serials;
359 is( @arrived_missing, 5, "GetSerials returns 5 arrived/missing by default" );
360 is( @others, 6, "GetSerials returns all serials not arrived and not missing" );
361
362 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid, 10 );
363 is( $total_issues, @statuses + 1, "GetSerials returns total_issues" );
364 @arrived_missing = map { my $status = $_->{status}; ( grep { /^$status$/ } qw( 2 4 41 42 43 44 5 ) ) ? $_ : () } @serials;
365 @others = map { my $status = $_->{status}; ( grep { /^$status$/ } qw( 2 4 41 42 43 44 5 ) ) ? () : $_ } @serials;
366 is( @arrived_missing, 9, "GetSerials returns all arrived/missing if count given" );
367 is( @others, 6, "GetSerials returns all serials not arrived and not missing if count given" );
368
369 $subscription = C4::Serials::GetSubscription($subscriptionid); # Retrieve the updated subscription
370
371 my @serialseqs;
372 for my $am ( @arrived_missing ) {
373     if ( grep {/^$am->{status}$/} qw( 4 41 42 43 44 ) ) {
374         push @serialseqs, $am->{serialseq}
375     } elsif ( grep {/^$am->{status}$/} qw( 5 ) ) {
376         push @serialseqs, 'not issued ' . $am->{serialseq};
377     }
378 }
379 is( $subscription->{missinglist}, join('; ', @serialseqs), "subscription missinglist is updated after ModSerialStatus" );
380
381 subtest "Do not generate an expected if one already exists" => sub {
382     plan tests => 2;
383     my ($expected_serial) = GetSerials2( $subscriptionid, [1] );
384
385     #Find serialid for serial with status Expected
386     my $serialexpected = ( C4::Serials::findSerialsByStatus( 1, $subscriptionid ) )[0];
387
388     #delete serial with status Expected
389     C4::Serials::ModSerialStatus( $serialexpected->{serialid}, $serialexpected->{serialseq}, $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
390     @serialsByStatus = C4::Serials::findSerialsByStatus( 1, $subscriptionid );
391     is( @serialsByStatus, 1, "ModSerialStatus delete corectly serial expected and create another if not exist" );
392
393     # add 1 serial with status=Expected 1
394     C4::Serials::ModSerialStatus( $expected_serial->{serialid}, 'NO.20', $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
395
396     #Now we have two serials it have status expected
397     #put status delete for last serial
398     C4::Serials::ModSerialStatus( $serialexpected->{serialid}, $serialexpected->{serialseq}, $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
399
400     #try if create or not another serial with status is expected
401     @serialsByStatus = C4::Serials::findSerialsByStatus( 1, $subscriptionid );
402     is( @serialsByStatus, 1, "ModSerialStatus delete corectly serial expected and not create another if exists" );
403 };
404
405 subtest "PreserveSerialNotes preference" => sub {
406     plan tests => 2;
407     my ($expected_serial) = GetSerials2( $subscriptionid, [1] );
408
409     t::lib::Mocks::mock_preference( 'PreserveSerialNotes', 1 );
410
411     C4::Serials::ModSerialStatus( $expected_serial->{serialid}, 'NO.20', $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
412     @serialsByStatus = C4::Serials::findSerialsByStatus( 1, $subscriptionid );
413     is( $serialsByStatus[0]->{note},$expected_serial->{note}, "note passed through if supposed to");
414
415     t::lib::Mocks::mock_preference( 'PreserveSerialNotes', 0 );
416     $expected_serial = $serialsByStatus[0];
417     C4::Serials::ModSerialStatus( $expected_serial->{serialid}, 'NO.20', $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
418     is( $serialsByStatus[0]->{note},$expected_serial->{note}, "note not passed through if not supposed to");
419
420 };
421
422 subtest "NewSubscription" => sub {
423     plan tests => 1;
424     my $subscriptionid = NewSubscription(
425         "",      "",     "", "", $budget_id, $biblionumber,
426         '2013-01-01', $frequency_id, "", "",  "",
427         "",      "",  "", "", "", "",
428         1,          $notes,"", '2013-01-01', "", $pattern_id,
429         "",       "",  0,    $internalnotes,  0,
430         "", "", 0,          "",         '2013-12-31', 0
431     );
432     ok($subscriptionid, "Sending empty string instead of undef to reflect use of the interface");
433 };