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