3 # This Koha test module is a stub!
4 # Add more tests here!!!
8 use C4::Serials qw( updateClaim NewSubscription GetSubscription GetSubscriptionHistoryFromSubscriptionId SearchSubscriptions ModSubscription GetExpirationDate GetSerials GetSerialInformation NewIssue AddItem2Serial DelSubscription GetFullSubscription PrepareSerialsData GetSubscriptionsFromBiblionumber ModSubscriptionHistory GetSerials2 GetLatestSerials GetNextSeq GetSeq CountSubscriptionFromBiblionumber ModSerialStatus findSerialsByStatus HasSubscriptionStrictlyExpired HasSubscriptionExpired GetLateOrMissingIssues check_routing addroutingmember GetNextDate );
9 use C4::Serials::Frequency;
10 use C4::Serials::Numberpattern;
11 use C4::Biblio qw( AddBiblio GetMarcFromKohaField );
12 use C4::Budgets qw( AddBudgetPeriod AddBudget );
13 use C4::Items qw( AddItemFromMarc );
15 use Koha::DateUtils qw( dt_from_string output_pref );
16 use Koha::Acquisition::Booksellers;
18 use t::lib::TestBuilder;
20 use Test::More tests => 54;
23 use_ok('C4::Serials', qw( updateClaim NewSubscription GetSubscription GetSubscriptionHistoryFromSubscriptionId SearchSubscriptions ModSubscription GetExpirationDate GetSerials GetSerialInformation NewIssue AddItem2Serial DelSubscription GetFullSubscription PrepareSerialsData GetSubscriptionsFromBiblionumber ModSubscriptionHistory GetSerials2 GetLatestSerials GetNextSeq GetSeq CountSubscriptionFromBiblionumber ModSerialStatus findSerialsByStatus HasSubscriptionStrictlyExpired HasSubscriptionExpired GetLateOrMissingIssues check_routing addroutingmember GetNextDate ));
26 # Auth required for cataloguing plugins
27 my $mAuth = Test::MockModule->new('C4::Auth');
28 $mAuth->mock( 'check_cookie_auth', sub { return ('ok') } );
30 my $schema = Koha::Database->new->schema;
31 $schema->storage->txn_begin;
32 my $dbh = C4::Context->dbh;
34 $dbh->do('DELETE FROM subscription');
36 my $builder = t::lib::TestBuilder->new();
38 # This could/should be used for all untested methods
39 my @methods = ('updateClaim');
40 can_ok('C4::Serials', @methods);
42 $dbh->do(q|UPDATE marc_subfield_structure SET value_builder="callnumber.pl" where kohafield="items.itemcallnumber" and frameworkcode=''|);
44 my $bookseller = Koha::Acquisition::Bookseller->new(
47 address1 => "bookseller's address",
53 my ($biblionumber, $biblioitemnumber) = AddBiblio(MARC::Record->new, '');
55 my $bpid = AddBudgetPeriod({
56 budget_period_startdate => '2015-01-01',
57 budget_period_enddate => '2015-12-31',
58 budget_period_description => "budget desc"
61 my $budget_id = AddBudget({
62 budget_code => "ABCD",
63 budget_amount => "123.132",
64 budget_name => "Périodiques",
65 budget_notes => "This is a note",
66 budget_period_id => $bpid
69 my $frequency_id = AddSubscriptionFrequency({ description => "Test frequency 1" });
70 my $pattern_id = AddSubscriptionNumberpattern({
71 label => 'Test numberpattern 1',
72 description => 'Description for numberpattern 1',
73 numberingmethod => '{X}',
82 my $notes = "a\nnote\non\nseveral\nlines";
83 my $internalnotes = 'intnotes';
85 my $subscriptionid = NewSubscription(
166 my $subscriptioninformation = GetSubscription( $subscriptionid );
168 is( $subscriptioninformation->{notes}, $notes, 'NewSubscription should set notes' );
169 is( $subscriptioninformation->{internalnotes}, $internalnotes, 'NewSubscription should set internalnotes' );
170 is( $subscriptioninformation->{ccode}, $ccode, 'NewSubscription should set ccode' );
172 my $subscription_history = C4::Serials::GetSubscriptionHistoryFromSubscriptionId($subscriptionid);
173 is( $subscription_history->{opacnote}, undef, 'NewSubscription should not set subscriptionhistory opacnotes' );
174 is( $subscription_history->{librariannote}, undef, 'NewSubscription should not set subscriptionhistory librariannotes' );
176 my @subscriptions = SearchSubscriptions({string => $subscriptioninformation->{bibliotitle}, orderby => 'title' });
177 isa_ok( \@subscriptions, 'ARRAY' );
179 @subscriptions = SearchSubscriptions({ issn => $subscriptioninformation->{issn}, orderby => 'title' });
180 isa_ok( \@subscriptions, 'ARRAY' );
182 @subscriptions = SearchSubscriptions({ ean => $subscriptioninformation->{ean}, orderby => 'title' });
183 isa_ok( \@subscriptions, 'ARRAY' );
185 @subscriptions = SearchSubscriptions({ biblionumber => $subscriptioninformation->{bibnum}, orderby => 'title' });
186 isa_ok( \@subscriptions, 'ARRAY' );
188 @subscriptions = SearchSubscriptions({});
192 'SearchSubscriptions returned the expected number of subscriptions when results_limit is not set'
195 @subscriptions = SearchSubscriptions({}, { results_limit => 1 });
199 'SearchSubscriptions returned only one subscription when results_limit is set to "1"'
202 my $frequency = GetSubscriptionFrequency($subscriptioninformation->{periodicity});
204 if (not $frequency->{unit}) {
205 $old_frequency = $frequency->{id};
206 $frequency->{unit} = "month";
207 $frequency->{unitsperissue} = 1;
208 $frequency->{issuesperunit} = 1;
209 $frequency->{description} = "Frequency created by t/db_dependant/Serials.t";
210 $subscriptioninformation->{periodicity} = AddSubscriptionFrequency($frequency);
211 $subscriptioninformation->{serialsadditems} = 1;
212 $subscriptioninformation->{ccode} = 'NFIC';
214 ModSubscription( @$subscriptioninformation{qw(
215 librarian branchcode aqbooksellerid cost aqbudgetid startdate
216 periodicity firstacquidate irregularity numberpattern locale
217 numberlength weeklength monthlength lastvalue1 innerloop1 lastvalue2
218 innerloop2 lastvalue3 innerloop3 status biblionumber callnumber notes
219 letter manualhistory internalnotes serialsadditems staffdisplaycount
220 opacdisplaycount graceperiod location enddate subscriptionid
221 skip_serialseq itemtype previousitemtype mana_id ccode
224 my $expirationdate = GetExpirationDate($subscriptionid) ;
225 ok( $expirationdate, "expiration date is not NULL" );
227 # Check ModSubscription has updated the ccode
228 my $subscriptioninformation2 = GetSubscription($subscriptionid);
229 is( $subscriptioninformation2->{ccode}, 'NFIC', 'ModSubscription should update ccode' );
231 ok(C4::Serials::GetSubscriptionHistoryFromSubscriptionId($subscriptionid), 'test getting history from sub-scription');
233 my ($serials_count, @serials) = GetSerials($subscriptionid);
234 ok($serials_count > 0, 'Subscription has at least one serial');
235 my $serial = $serials[0];
237 isa_ok(C4::Serials::GetSerialInformation($serial->{serialid}), 'HASH', 'test getting Serial Information');
239 subtest 'Values should not be erased on editing' => sub {
243 my $biblio = $builder->build_sample_biblio();
244 my $biblionumber = $biblio->biblionumber;
245 my ( $icn_tag, $icn_sf ) = GetMarcFromKohaField( 'items.itemcallnumber' );
246 my ( $it_tag, $it_sf ) = GetMarcFromKohaField( 'items.itype' );
248 my $itemtype = $builder->build( { source => 'Itemtype' } )->{itemtype};
249 my $itemcallnumber = 'XXXmy itemcallnumberXXX';
251 my $item_record = MARC::Record->new;
253 $item_record->append_fields(
254 MARC::Field->new( '080', '', '', "a" => "default" ),
257 $icn_sf => $itemcallnumber,
261 my ( undef, undef, $itemnumber ) = C4::Items::AddItemFromMarc( $item_record, $biblionumber );
262 my $serialid = C4::Serials::NewIssue( "serialseq", $subscriptionid, $biblionumber,
263 1, undef, undef, "publisheddatetext", "notes", "routingnotes" );
264 C4::Serials::AddItem2Serial( $serialid, $itemnumber );
265 my $serial_info = C4::Serials::GetSerialInformation($serialid);
266 my ($itemcallnumber_info) = grep { $_->{kohafield} eq 'items.itemcallnumber' }
267 @{ $serial_info->{items}[0]->{iteminformation} };
268 like( $itemcallnumber_info->{marc_value}, qr|value="$itemcallnumber"| );
271 # Delete created frequency
272 if ($old_frequency) {
273 my $freq_to_delete = $subscriptioninformation->{periodicity};
274 $subscriptioninformation->{periodicity} = $old_frequency;
276 ModSubscription( @$subscriptioninformation{qw(
277 librarian branchcode aqbooksellerid cost aqbudgetid startdate
278 periodicity firstacquidate irregularity numberpattern locale
279 numberlength weeklength monthlength lastvalue1 innerloop1 lastvalue2
280 innerloop2 lastvalue3 innerloop3 status biblionumber callnumber notes
281 letter manualhistory internalnotes serialsadditems staffdisplaycount
282 opacdisplaycount graceperiod location enddate subscriptionid
286 DelSubscriptionFrequency($freq_to_delete);
289 # Test calling subs without parameters
290 is(C4::Serials::AddItem2Serial(), undef, 'test adding item to serial');
291 is(C4::Serials::GetFullSubscription(), undef, 'test getting full subscription');
292 is(C4::Serials::PrepareSerialsData(), undef, 'test preparing serial data');
294 subtest 'GetSubscriptionsFromBiblionumber' => sub {
297 is( C4::Serials::GetSubscriptionsFromBiblionumber(),
298 undef, 'test getting subscriptions form biblio number' );
300 my $subscriptions = C4::Serials::GetSubscriptionsFromBiblionumber($biblionumber);
301 ModSubscriptionHistory( $subscriptions->[0]->{subscriptionid},
302 undef, undef, $notes, $notes, $notes );
304 $subscriptions = C4::Serials::GetSubscriptionsFromBiblionumber($biblionumber);
305 is( $subscriptions->[0]->{opacnote}, $notes,
306 'GetSubscriptionsFromBiblionumber should have returned the opacnote as it is in DB, ie. without br tags'
308 is( $subscriptions->[0]->{recievedlist}, $notes,
309 'GetSubscriptionsFromBiblionumber should have returned recievedlist as it is in DB, ie. without br tags'
311 is( $subscriptions->[0]->{missinglist}, $notes,
312 'GetSubscriptionsFromBiblionumber should have returned missinglist as it is in DB, ie. without br tags'
316 is(C4::Serials::GetSerials(), undef, 'test getting serials when you enter nothing');
317 is(C4::Serials::GetSerials2(), undef, 'test getting serials when you enter nothing');
319 is(C4::Serials::GetLatestSerials(), undef, 'test getting lastest serials');
321 is(C4::Serials::GetNextSeq(), undef, 'test getting next seq when you enter nothing');
323 is(C4::Serials::GetSeq(), undef, 'test getting seq when you enter nothing');
325 is(C4::Serials::CountSubscriptionFromBiblionumber(), undef, 'test counting subscription when nothing is entered');
327 is(C4::Serials::ModSubscriptionHistory(), undef, 'test modding subscription history');
329 is(C4::Serials::ModSerialStatus(),undef, 'test modding serials');
331 is(C4::Serials::findSerialsByStatus(), 0, 'test finding serial by status with no parameters');
333 is(C4::Serials::NewIssue(), undef, 'test getting 0 when nothing is entered');
335 is(C4::Serials::HasSubscriptionStrictlyExpired(), undef, 'test if the subscriptions has expired');
336 is(C4::Serials::HasSubscriptionExpired(), undef, 'test if the subscriptions has expired');
338 is(C4::Serials::GetLateOrMissingIssues(), undef, 'test getting last or missing issues');
340 subtest 'test_updateClaim' => sub {
343 my $today = output_pref({ dt => dt_from_string, dateonly => 1 });
344 # Given ... nothing much
346 my $result_0 = C4::Serials::updateClaim(undef);
347 is($result_0, undef, 'Got the expected undef from update claim with nothin');
349 # Given ... 3 serial. 2 of them updated.
350 my $claimdate_1 = dt_from_string('2001-01-13'); # arbitrary date some time in the past.
351 my $claim_count_1 = 5;
352 my $biblio = $builder->build_sample_biblio;
353 my $serial1 = $builder->build_object(
355 class => 'Koha::Serials',
357 serialseq => 'serialseq',
358 subscriptionid => $subscriptionid,
360 biblionumber => $biblio->biblionumber,
361 claimdate => $claimdate_1,
362 claims_count => $claim_count_1,
366 my $serial2 = $builder->build_object(
368 class => 'Koha::Serials',
370 serialseq => 'serialseq',
371 subscriptionid => $subscriptionid,
373 biblionumber => $biblio->biblionumber,
374 claimdate => $claimdate_1,
375 claims_count => $claim_count_1,
379 my $serial3 = $builder->build_object(
381 class => 'Koha::Serials',
383 serialseq => 'serialseq',
384 subscriptionid => $subscriptionid,
386 biblionumber => $biblio->biblionumber,
387 claimdate => $claimdate_1,
388 claims_count => $claim_count_1,
394 my $result_1 = C4::Serials::updateClaim([$serial1->serialid, $serial2->serialid]);
397 is($result_1, 2, 'Got the expected 2 from update claim with 2 serial ids');
399 my @late_or_missing_issues_1_0 = C4::Serials::GetLateOrMissingIssues(undef, $serial1->serialid);
400 is(output_pref({str => $late_or_missing_issues_1_0[0]->{claimdate}, dateonly => 1}), $today, 'Got the expected first different claim date from update claim');
401 is($late_or_missing_issues_1_0[0]->{claims_count}, $claim_count_1+1, 'Got the expected first claim count from update claim');
402 is($late_or_missing_issues_1_0[0]->{status}, 7, 'Got the expected first claim status from update claim');
404 my @late_or_missing_issues_1_1 = C4::Serials::GetLateOrMissingIssues(undef, $serial2->serialid);
405 is(output_pref({str => $late_or_missing_issues_1_1[0]->{claimdate}, dateonly => 1}), $today, 'Got the expected second different claim date from update claim');
406 is($late_or_missing_issues_1_1[0]->{claims_count}, $claim_count_1+1, 'Got the expected second claim count from update claim');
407 is($late_or_missing_issues_1_1[0]->{status}, 7, 'Got the expected second claim status from update claim');
409 my @late_or_missing_issues_1_2 = C4::Serials::GetLateOrMissingIssues(undef, $serial3->serialid);
410 is(output_pref({str => $late_or_missing_issues_1_2[0]->{claimdate}, dateonly => 1}), output_pref({ dt => $claimdate_1, dateonly => 1}), 'Got the expected unchanged claim date from update claim');
411 is($late_or_missing_issues_1_2[0]->{claims_count}, $claim_count_1, 'Got the expected unchanged claim count from update claim');
412 is($late_or_missing_issues_1_2[0]->{status}, 3, 'Got the expected unchanged claim status from update claim');
415 is(C4::Serials::check_routing(), undef, 'test checking route');
416 is(C4::Serials::check_routing($subscriptionid), 0, 'There should not have any routing list for the subscription');
417 # TODO really test this check_routing subroutine
419 is(C4::Serials::addroutingmember(),undef, 'test adding route member');
422 # Unit tests for statuses management (Bug 11689)
423 $subscriptionid = NewSubscription(
424 undef, "", undef, undef, $budget_id, $biblionumber,
425 '2013-01-01', $frequency_id, undef, undef, undef,
426 undef, undef, undef, undef, undef, undef,
427 1, $notes,undef, '2013-01-01', undef, $pattern_id,
428 undef, undef, 0, $internalnotes, 0,
429 undef, undef, 0, undef, '2013-12-31', 0
432 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid );
433 is( $total_issues, 1, "NewSubscription created a first serial" );
434 is( @serials, 1, "GetSerials returns the serial" );
435 my $subscription = C4::Serials::GetSubscription($subscriptionid);
436 my $pattern = C4::Serials::Numberpattern::GetSubscriptionNumberpattern($subscription->{numberpattern});
437 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid );
438 my $publisheddate = output_pref({ dt => dt_from_string, dateformat => 'iso', dateonly => 1 });
439 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid );
440 $frequency = C4::Serials::Frequency::GetSubscriptionFrequency($subscription->{periodicity});
441 my $nextpublisheddate = C4::Serials::GetNextDate($subscription, $publisheddate, $frequency, 1);
442 my @statuses = qw( 2 2 3 3 3 3 3 4 4 41 42 43 44 5 );
445 for my $status ( @statuses ) {
446 my $serialseq = "No.".$counter;
447 my ( $expected_serial ) = GetSerials2( $subscriptionid, [1] );
448 C4::Serials::ModSerialStatus( $expected_serial->{serialid}, $serialseq, $publisheddate, $publisheddate, $publisheddate, $statuses[$counter], 'an useless note' );
451 # 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
452 my @serialsByStatus = C4::Serials::findSerialsByStatus(2,$subscriptionid);
453 is(@serialsByStatus,2,"findSerialsByStatus returns all serials with chosen status");
454 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid );
455 is( $total_issues, @statuses + 1, "GetSerials returns total_issues" );
456 my @arrived_missing = map { my $status = $_->{status}; ( grep { /^$status$/ } qw( 2 4 41 42 43 44 5 ) ) ? $_ : () } @serials;
457 my @others = map { my $status = $_->{status}; ( grep { /^$status$/ } qw( 2 4 41 42 43 44 5 ) ) ? () : $_ } @serials;
458 is( @arrived_missing, 5, "GetSerials returns 5 arrived/missing by default" );
459 is( @others, 6, "GetSerials returns all serials not arrived and not missing" );
461 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid, 10 );
462 is( $total_issues, @statuses + 1, "GetSerials returns total_issues" );
463 @arrived_missing = map { my $status = $_->{status}; ( grep { /^$status$/ } qw( 2 4 41 42 43 44 5 ) ) ? $_ : () } @serials;
464 @others = map { my $status = $_->{status}; ( grep { /^$status$/ } qw( 2 4 41 42 43 44 5 ) ) ? () : $_ } @serials;
465 is( @arrived_missing, 9, "GetSerials returns all arrived/missing if count given" );
466 is( @others, 6, "GetSerials returns all serials not arrived and not missing if count given" );
468 $subscription = C4::Serials::GetSubscription($subscriptionid); # Retrieve the updated subscription
471 for my $am ( @arrived_missing ) {
472 if ( grep {/^$am->{status}$/} qw( 4 41 42 43 44 ) ) {
473 push @serialseqs, $am->{serialseq}
474 } elsif ( grep {/^$am->{status}$/} qw( 5 ) ) {
475 push @serialseqs, 'not issued ' . $am->{serialseq};
478 is( $subscription->{missinglist}, join('; ', @serialseqs), "subscription missinglist is updated after ModSerialStatus" );
480 subtest "Do not generate an expected if one already exists" => sub {
482 my ($expected_serial) = GetSerials2( $subscriptionid, [1] );
484 #Find serialid for serial with status Expected
485 my $serialexpected = ( C4::Serials::findSerialsByStatus( 1, $subscriptionid ) )[0];
487 #delete serial with status Expected
488 C4::Serials::ModSerialStatus( $serialexpected->{serialid}, $serialexpected->{serialseq}, $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
489 @serialsByStatus = C4::Serials::findSerialsByStatus( 1, $subscriptionid );
490 is( @serialsByStatus, 1, "ModSerialStatus delete corectly serial expected and create another if not exist" );
492 # add 1 serial with status=Expected 1
493 C4::Serials::ModSerialStatus( $expected_serial->{serialid}, 'NO.20', $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
495 #Now we have two serials it have status expected
496 #put status delete for last serial
497 C4::Serials::ModSerialStatus( $serialexpected->{serialid}, $serialexpected->{serialseq}, $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
499 #try if create or not another serial with status is expected
500 @serialsByStatus = C4::Serials::findSerialsByStatus( 1, $subscriptionid );
501 is( @serialsByStatus, 1, "ModSerialStatus delete corectly serial expected and not create another if exists" );
504 subtest "PreserveSerialNotes preference" => sub {
506 my ($expected_serial) = GetSerials2( $subscriptionid, [1] );
508 t::lib::Mocks::mock_preference( 'PreserveSerialNotes', 1 );
510 C4::Serials::ModSerialStatus( $expected_serial->{serialid}, 'NO.20', $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
511 @serialsByStatus = C4::Serials::findSerialsByStatus( 1, $subscriptionid );
512 is( $serialsByStatus[0]->{note},$expected_serial->{note}, "note passed through if supposed to");
514 t::lib::Mocks::mock_preference( 'PreserveSerialNotes', 0 );
515 $expected_serial = $serialsByStatus[0];
516 C4::Serials::ModSerialStatus( $expected_serial->{serialid}, 'NO.20', $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
517 is( $serialsByStatus[0]->{note},$expected_serial->{note}, "note not passed through if not supposed to");
521 subtest "NewSubscription|ModSubscription" => sub {
523 my $subscriptionid = NewSubscription(
524 "", "", "", "", $budget_id, $biblionumber,
525 '2013-01-01', $frequency_id, "", "", "",
526 "", "", "", "", "", "",
527 1, $notes,"", '2013-01-01', "", $pattern_id,
528 "", "", 0, $internalnotes, 0,
529 "", "", 0, "", '2013-12-31', 0
531 ok($subscriptionid, "Sending empty string instead of undef to reflect use of the interface");
533 my $subscription = Koha::Subscriptions->find($subscriptionid);
534 my $serials = Koha::Serials->search({ subscriptionid => $subscriptionid });
535 is( $serials->count, 1, "NewSubscription created a first serial" );
537 my $biblio_2 = $builder->build_sample_biblio;
538 my $subscription_info = $subscription->unblessed;
539 $subscription_info->{biblionumber} = $biblio_2->biblionumber;
540 ModSubscription( @$subscription_info{qw(
541 librarian branchcode aqbooksellerid cost aqbudgetid startdate
542 periodicity firstacquidate irregularity numberpattern locale
543 numberlength weeklength monthlength lastvalue1 innerloop1 lastvalue2
544 innerloop2 lastvalue3 innerloop3 status biblionumber callnumber notes
545 letter manualhistory internalnotes serialsadditems staffdisplaycount
546 opacdisplaycount graceperiod location enddate subscriptionid
550 $serials = Koha::Serials->search({ subscriptionid => $subscriptionid });
551 is( $serials->count, 1, "Still only one serial" );
552 is( $serials->next->biblionumber, $biblio_2->biblionumber, 'ModSubscription should have updated serial.biblionumber');
555 subtest "_numeration" => sub {
559 my $s = C4::Serials::_numeration(0, 'monthname', 'cat');
561 $s = C4::Serials::_numeration(0, 'monthname', 'es');
563 $s = C4::Serials::_numeration(0, 'monthname', 'fr');
566 $s = C4::Serials::_numeration(0, 'monthabrv', 'cat');
568 $s = C4::Serials::_numeration(0, 'monthabrv', 'es');
569 like( $s, qr{^ene\.?} );
570 $s = C4::Serials::_numeration(0, 'monthabrv', 'fr');