3 # This Koha test module is a stub!
4 # Add more tests here!!!
9 use C4::Serials::Frequency;
10 use C4::Serials::Numberpattern;
17 use Koha::Acquisition::Booksellers;
19 use t::lib::TestBuilder;
20 use Test::More tests => 49;
23 use_ok('C4::Serials');
26 my $schema = Koha::Database->new->schema;
27 $schema->storage->txn_begin;
28 my $dbh = C4::Context->dbh;
30 my $builder = t::lib::TestBuilder->new();
32 # This could/should be used for all untested methods
33 my @methods = ('updateClaim');
34 can_ok('C4::Serials', @methods);
36 $dbh->do(q|UPDATE marc_subfield_structure SET value_builder="callnumber.pl" where kohafield="items.itemcallnumber" and frameworkcode=''|);
38 my $bookseller = Koha::Acquisition::Bookseller->new(
41 address1 => "bookseller's address",
47 my ($biblionumber, $biblioitemnumber) = AddBiblio(MARC::Record->new, '');
49 my $bpid = AddBudgetPeriod({
50 budget_period_startdate => '2015-01-01',
51 budget_period_enddate => '2015-12-31',
52 budget_period_description => "budget desc"
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
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}',
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
87 my $subscriptioninformation = GetSubscription( $subscriptionid );
89 is( $subscriptioninformation->{notes}, $notes, 'NewSubscription should set notes' );
90 is( $subscriptioninformation->{internalnotes}, $internalnotes, 'NewSubscription should set internalnotes' );
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' );
96 my @subscriptions = SearchSubscriptions({string => $subscriptioninformation->{bibliotitle}, orderby => 'title' });
97 isa_ok( \@subscriptions, 'ARRAY' );
99 @subscriptions = SearchSubscriptions({ issn => $subscriptioninformation->{issn}, orderby => 'title' });
100 isa_ok( \@subscriptions, 'ARRAY' );
102 @subscriptions = SearchSubscriptions({ ean => $subscriptioninformation->{ean}, orderby => 'title' });
103 isa_ok( \@subscriptions, 'ARRAY' );
105 @subscriptions = SearchSubscriptions({ biblionumber => $subscriptioninformation->{bibnum}, orderby => 'title' });
106 isa_ok( \@subscriptions, 'ARRAY' );
108 my $frequency = GetSubscriptionFrequency($subscriptioninformation->{periodicity});
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;
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
129 my $expirationdate = GetExpirationDate($subscriptionid) ;
130 ok( $expirationdate, "expiration date is not NULL" );
132 ok(C4::Serials::GetSubscriptionHistoryFromSubscriptionId($subscriptionid), 'test getting history from sub-scription');
134 my ($serials_count, @serials) = GetSerials($subscriptionid);
135 ok($serials_count > 0, 'Subscription has at least one serial');
136 my $serial = $serials[0];
138 isa_ok(C4::Serials::GetSerialInformation($serial->{serialid}), 'HASH', 'test getting Serial Information');
140 subtest 'Values should not be erased on editing' => sub {
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' );
149 my $itemtype = $builder->build( { source => 'Itemtype' } )->{itemtype};
150 my $itemcallnumber = 'XXXmy itemcallnumberXXX';
152 my $item_record = MARC::Record->new;
154 $item_record->append_fields(
155 MARC::Field->new( '080', '', '', "a" => "default" ),
158 $icn_sf => $itemcallnumber,
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"| );
172 # Delete created frequency
173 if ($old_frequency) {
174 my $freq_to_delete = $subscriptioninformation->{periodicity};
175 $subscriptioninformation->{periodicity} = $old_frequency;
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
187 DelSubscriptionFrequency($freq_to_delete);
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');
195 subtest 'GetSubscriptionsFromBiblionumber' => sub {
198 is( C4::Serials::GetSubscriptionsFromBiblionumber(),
199 undef, 'test getting subscriptions form biblio number' );
201 my $subscriptions = C4::Serials::GetSubscriptionsFromBiblionumber($biblionumber);
202 ModSubscriptionHistory( $subscriptions->[0]->{subscriptionid},
203 undef, undef, $notes, $notes, $notes );
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'
209 is( $subscriptions->[0]->{recievedlist}, $notes,
210 'GetSubscriptionsFromBiblionumber should have returned recievedlist as it is in DB, ie. without br tags'
212 is( $subscriptions->[0]->{missinglist}, $notes,
213 'GetSubscriptionsFromBiblionumber should have returned missinglist as it is in DB, ie. without br tags'
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');
220 is(C4::Serials::GetLatestSerials(), undef, 'test getting lastest serials');
222 is(C4::Serials::GetNextSeq(), undef, 'test getting next seq when you enter nothing');
224 is(C4::Serials::GetSeq(), undef, 'test getting seq when you enter nothing');
226 is(C4::Serials::CountSubscriptionFromBiblionumber(), undef, 'test counting subscription when nothing is entered');
228 is(C4::Serials::ModSubscriptionHistory(), undef, 'test modding subscription history');
230 is(C4::Serials::ModSerialStatus(),undef, 'test modding serials');
232 is(C4::Serials::findSerialsByStatus(), 0, 'test finding serial by status with no parameters');
234 is(C4::Serials::NewIssue(), undef, 'test getting 0 when nothing is entered');
236 is(C4::Serials::HasSubscriptionStrictlyExpired(), undef, 'test if the subscriptions has expired');
237 is(C4::Serials::HasSubscriptionExpired(), undef, 'test if the subscriptions has expired');
239 is(C4::Serials::GetLateOrMissingIssues(), undef, 'test getting last or missing issues');
241 subtest 'test_updateClaim' => sub {
244 my $today = output_pref({ dt => dt_from_string, dateonly => 1 });
245 # Given ... nothing much
247 my $result_0 = C4::Serials::updateClaim(undef);
248 is($result_0, undef, 'Got the expected undef from update claim with nothin');
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(
256 class => 'Koha::Serials',
258 serialseq => 'serialseq',
259 subscriptionid => $subscriptionid,
261 biblionumber => $biblio->biblionumber,
262 claimdate => $claimdate_1,
263 claims_count => $claim_count_1,
267 my $serial2 = $builder->build_object(
269 class => 'Koha::Serials',
271 serialseq => 'serialseq',
272 subscriptionid => $subscriptionid,
274 biblionumber => $biblio->biblionumber,
275 claimdate => $claimdate_1,
276 claims_count => $claim_count_1,
280 my $serial3 = $builder->build_object(
282 class => 'Koha::Serials',
284 serialseq => 'serialseq',
285 subscriptionid => $subscriptionid,
287 biblionumber => $biblio->biblionumber,
288 claimdate => $claimdate_1,
289 claims_count => $claim_count_1,
295 my $result_1 = C4::Serials::updateClaim([$serial1->serialid, $serial2->serialid]);
298 is($result_1, 2, 'Got the expected 2 from update claim with 2 serial ids');
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');
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');
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');
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
320 is(C4::Serials::addroutingmember(),undef, 'test adding route member');
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
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 );
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' );
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" );
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" );
369 $subscription = C4::Serials::GetSubscription($subscriptionid); # Retrieve the updated subscription
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};
379 is( $subscription->{missinglist}, join('; ', @serialseqs), "subscription missinglist is updated after ModSerialStatus" );
381 subtest "Do not generate an expected if one already exists" => sub {
383 my ($expected_serial) = GetSerials2( $subscriptionid, [1] );
385 #Find serialid for serial with status Expected
386 my $serialexpected = ( C4::Serials::findSerialsByStatus( 1, $subscriptionid ) )[0];
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" );
393 # add 1 serial with status=Expected 1
394 C4::Serials::ModSerialStatus( $expected_serial->{serialid}, 'NO.20', $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
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' );
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" );
405 subtest "PreserveSerialNotes preference" => sub {
407 my ($expected_serial) = GetSerials2( $subscriptionid, [1] );
409 t::lib::Mocks::mock_preference( 'PreserveSerialNotes', 1 );
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");
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");
422 subtest "NewSubscription" => sub {
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
432 ok($subscriptionid, "Sending empty string instead of undef to reflect use of the interface");