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;
19 use Test::More tests => 54;
22 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 ));
25 my $schema = Koha::Database->new->schema;
26 $schema->storage->txn_begin;
27 my $dbh = C4::Context->dbh;
29 $dbh->do('DELETE FROM subscription');
31 my $builder = t::lib::TestBuilder->new();
33 # This could/should be used for all untested methods
34 my @methods = ('updateClaim');
35 can_ok('C4::Serials', @methods);
37 $dbh->do(q|UPDATE marc_subfield_structure SET value_builder="callnumber.pl" where kohafield="items.itemcallnumber" and frameworkcode=''|);
39 my $bookseller = Koha::Acquisition::Bookseller->new(
42 address1 => "bookseller's address",
48 my ($biblionumber, $biblioitemnumber) = AddBiblio(MARC::Record->new, '');
50 my $bpid = AddBudgetPeriod({
51 budget_period_startdate => '2015-01-01',
52 budget_period_enddate => '2015-12-31',
53 budget_period_description => "budget desc"
56 my $budget_id = AddBudget({
57 budget_code => "ABCD",
58 budget_amount => "123.132",
59 budget_name => "Périodiques",
60 budget_notes => "This is a note",
61 budget_period_id => $bpid
64 my $frequency_id = AddSubscriptionFrequency({ description => "Test frequency 1" });
65 my $pattern_id = AddSubscriptionNumberpattern({
66 label => 'Test numberpattern 1',
67 description => 'Description for numberpattern 1',
68 numberingmethod => '{X}',
77 my $notes = "a\nnote\non\nseveral\nlines";
78 my $internalnotes = 'intnotes';
80 my $subscriptionid = NewSubscription(
161 my $subscriptioninformation = GetSubscription( $subscriptionid );
163 is( $subscriptioninformation->{notes}, $notes, 'NewSubscription should set notes' );
164 is( $subscriptioninformation->{internalnotes}, $internalnotes, 'NewSubscription should set internalnotes' );
165 is( $subscriptioninformation->{ccode}, $ccode, 'NewSubscription should set ccode' );
167 my $subscription_history = C4::Serials::GetSubscriptionHistoryFromSubscriptionId($subscriptionid);
168 is( $subscription_history->{opacnote}, undef, 'NewSubscription should not set subscriptionhistory opacnotes' );
169 is( $subscription_history->{librariannote}, undef, 'NewSubscription should not set subscriptionhistory librariannotes' );
171 my @subscriptions = SearchSubscriptions({string => $subscriptioninformation->{bibliotitle}, orderby => 'title' });
172 isa_ok( \@subscriptions, 'ARRAY' );
174 @subscriptions = SearchSubscriptions({ issn => $subscriptioninformation->{issn}, orderby => 'title' });
175 isa_ok( \@subscriptions, 'ARRAY' );
177 @subscriptions = SearchSubscriptions({ ean => $subscriptioninformation->{ean}, orderby => 'title' });
178 isa_ok( \@subscriptions, 'ARRAY' );
180 @subscriptions = SearchSubscriptions({ biblionumber => $subscriptioninformation->{bibnum}, orderby => 'title' });
181 isa_ok( \@subscriptions, 'ARRAY' );
183 @subscriptions = SearchSubscriptions({});
187 'SearchSubscriptions returned the expected number of subscriptions when results_limit is not set'
190 @subscriptions = SearchSubscriptions({}, { results_limit => 1 });
194 'SearchSubscriptions returned only one subscription when results_limit is set to "1"'
197 my $frequency = GetSubscriptionFrequency($subscriptioninformation->{periodicity});
199 if (not $frequency->{unit}) {
200 $old_frequency = $frequency->{id};
201 $frequency->{unit} = "month";
202 $frequency->{unitsperissue} = 1;
203 $frequency->{issuesperunit} = 1;
204 $frequency->{description} = "Frequency created by t/db_dependant/Serials.t";
205 $subscriptioninformation->{periodicity} = AddSubscriptionFrequency($frequency);
206 $subscriptioninformation->{serialsadditems} = 1;
207 $subscriptioninformation->{ccode} = 'NFIC';
209 ModSubscription( @$subscriptioninformation{qw(
210 librarian branchcode aqbooksellerid cost aqbudgetid startdate
211 periodicity firstacquidate irregularity numberpattern locale
212 numberlength weeklength monthlength lastvalue1 innerloop1 lastvalue2
213 innerloop2 lastvalue3 innerloop3 status biblionumber callnumber notes
214 letter manualhistory internalnotes serialsadditems staffdisplaycount
215 opacdisplaycount graceperiod location enddate subscriptionid
216 skip_serialseq itemtype previousitemtype mana_id ccode
219 my $expirationdate = GetExpirationDate($subscriptionid) ;
220 ok( $expirationdate, "expiration date is not NULL" );
222 # Check ModSubscription has updated the ccode
223 my $subscriptioninformation2 = GetSubscription($subscriptionid);
224 is( $subscriptioninformation2->{ccode}, 'NFIC', 'ModSubscription should update ccode' );
226 ok(C4::Serials::GetSubscriptionHistoryFromSubscriptionId($subscriptionid), 'test getting history from sub-scription');
228 my ($serials_count, @serials) = GetSerials($subscriptionid);
229 ok($serials_count > 0, 'Subscription has at least one serial');
230 my $serial = $serials[0];
232 isa_ok(C4::Serials::GetSerialInformation($serial->{serialid}), 'HASH', 'test getting Serial Information');
234 subtest 'Values should not be erased on editing' => sub {
238 my $biblio = $builder->build_sample_biblio();
239 my $biblionumber = $biblio->biblionumber;
240 my ( $icn_tag, $icn_sf ) = GetMarcFromKohaField( 'items.itemcallnumber' );
241 my ( $it_tag, $it_sf ) = GetMarcFromKohaField( 'items.itype' );
243 my $itemtype = $builder->build( { source => 'Itemtype' } )->{itemtype};
244 my $itemcallnumber = 'XXXmy itemcallnumberXXX';
246 my $item_record = MARC::Record->new;
248 $item_record->append_fields(
249 MARC::Field->new( '080', '', '', "a" => "default" ),
252 $icn_sf => $itemcallnumber,
256 my ( undef, undef, $itemnumber ) = C4::Items::AddItemFromMarc( $item_record, $biblionumber );
257 my $serialid = C4::Serials::NewIssue( "serialseq", $subscriptionid, $biblionumber,
258 1, undef, undef, "publisheddatetext", "notes", "routingnotes" );
259 C4::Serials::AddItem2Serial( $serialid, $itemnumber );
260 my $serial_info = C4::Serials::GetSerialInformation($serialid);
261 my ($itemcallnumber_info) = grep { $_->{kohafield} eq 'items.itemcallnumber' }
262 @{ $serial_info->{items}[0]->{iteminformation} };
263 like( $itemcallnumber_info->{marc_value}, qr|value="$itemcallnumber"| );
266 # Delete created frequency
267 if ($old_frequency) {
268 my $freq_to_delete = $subscriptioninformation->{periodicity};
269 $subscriptioninformation->{periodicity} = $old_frequency;
271 ModSubscription( @$subscriptioninformation{qw(
272 librarian branchcode aqbooksellerid cost aqbudgetid startdate
273 periodicity firstacquidate irregularity numberpattern locale
274 numberlength weeklength monthlength lastvalue1 innerloop1 lastvalue2
275 innerloop2 lastvalue3 innerloop3 status biblionumber callnumber notes
276 letter manualhistory internalnotes serialsadditems staffdisplaycount
277 opacdisplaycount graceperiod location enddate subscriptionid
281 DelSubscriptionFrequency($freq_to_delete);
284 # Test calling subs without parameters
285 is(C4::Serials::AddItem2Serial(), undef, 'test adding item to serial');
286 is(C4::Serials::GetFullSubscription(), undef, 'test getting full subscription');
287 is(C4::Serials::PrepareSerialsData(), undef, 'test preparing serial data');
289 subtest 'GetSubscriptionsFromBiblionumber' => sub {
292 is( C4::Serials::GetSubscriptionsFromBiblionumber(),
293 undef, 'test getting subscriptions form biblio number' );
295 my $subscriptions = C4::Serials::GetSubscriptionsFromBiblionumber($biblionumber);
296 ModSubscriptionHistory( $subscriptions->[0]->{subscriptionid},
297 undef, undef, $notes, $notes, $notes );
299 $subscriptions = C4::Serials::GetSubscriptionsFromBiblionumber($biblionumber);
300 is( $subscriptions->[0]->{opacnote}, $notes,
301 'GetSubscriptionsFromBiblionumber should have returned the opacnote as it is in DB, ie. without br tags'
303 is( $subscriptions->[0]->{recievedlist}, $notes,
304 'GetSubscriptionsFromBiblionumber should have returned recievedlist as it is in DB, ie. without br tags'
306 is( $subscriptions->[0]->{missinglist}, $notes,
307 'GetSubscriptionsFromBiblionumber should have returned missinglist as it is in DB, ie. without br tags'
311 is(C4::Serials::GetSerials(), undef, 'test getting serials when you enter nothing');
312 is(C4::Serials::GetSerials2(), undef, 'test getting serials when you enter nothing');
314 is(C4::Serials::GetLatestSerials(), undef, 'test getting lastest serials');
316 is(C4::Serials::GetNextSeq(), undef, 'test getting next seq when you enter nothing');
318 is(C4::Serials::GetSeq(), undef, 'test getting seq when you enter nothing');
320 is(C4::Serials::CountSubscriptionFromBiblionumber(), undef, 'test counting subscription when nothing is entered');
322 is(C4::Serials::ModSubscriptionHistory(), undef, 'test modding subscription history');
324 is(C4::Serials::ModSerialStatus(),undef, 'test modding serials');
326 is(C4::Serials::findSerialsByStatus(), 0, 'test finding serial by status with no parameters');
328 is(C4::Serials::NewIssue(), undef, 'test getting 0 when nothing is entered');
330 is(C4::Serials::HasSubscriptionStrictlyExpired(), undef, 'test if the subscriptions has expired');
331 is(C4::Serials::HasSubscriptionExpired(), undef, 'test if the subscriptions has expired');
333 is(C4::Serials::GetLateOrMissingIssues(), undef, 'test getting last or missing issues');
335 subtest 'test_updateClaim' => sub {
338 my $today = output_pref({ dt => dt_from_string, dateonly => 1 });
339 # Given ... nothing much
341 my $result_0 = C4::Serials::updateClaim(undef);
342 is($result_0, undef, 'Got the expected undef from update claim with nothin');
344 # Given ... 3 serial. 2 of them updated.
345 my $claimdate_1 = dt_from_string('2001-01-13'); # arbitrary date some time in the past.
346 my $claim_count_1 = 5;
347 my $biblio = $builder->build_sample_biblio;
348 my $serial1 = $builder->build_object(
350 class => 'Koha::Serials',
352 serialseq => 'serialseq',
353 subscriptionid => $subscriptionid,
355 biblionumber => $biblio->biblionumber,
356 claimdate => $claimdate_1,
357 claims_count => $claim_count_1,
361 my $serial2 = $builder->build_object(
363 class => 'Koha::Serials',
365 serialseq => 'serialseq',
366 subscriptionid => $subscriptionid,
368 biblionumber => $biblio->biblionumber,
369 claimdate => $claimdate_1,
370 claims_count => $claim_count_1,
374 my $serial3 = $builder->build_object(
376 class => 'Koha::Serials',
378 serialseq => 'serialseq',
379 subscriptionid => $subscriptionid,
381 biblionumber => $biblio->biblionumber,
382 claimdate => $claimdate_1,
383 claims_count => $claim_count_1,
389 my $result_1 = C4::Serials::updateClaim([$serial1->serialid, $serial2->serialid]);
392 is($result_1, 2, 'Got the expected 2 from update claim with 2 serial ids');
394 my @late_or_missing_issues_1_0 = C4::Serials::GetLateOrMissingIssues(undef, $serial1->serialid);
395 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');
396 is($late_or_missing_issues_1_0[0]->{claims_count}, $claim_count_1+1, 'Got the expected first claim count from update claim');
397 is($late_or_missing_issues_1_0[0]->{status}, 7, 'Got the expected first claim status from update claim');
399 my @late_or_missing_issues_1_1 = C4::Serials::GetLateOrMissingIssues(undef, $serial2->serialid);
400 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');
401 is($late_or_missing_issues_1_1[0]->{claims_count}, $claim_count_1+1, 'Got the expected second claim count from update claim');
402 is($late_or_missing_issues_1_1[0]->{status}, 7, 'Got the expected second claim status from update claim');
404 my @late_or_missing_issues_1_2 = C4::Serials::GetLateOrMissingIssues(undef, $serial3->serialid);
405 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');
406 is($late_or_missing_issues_1_2[0]->{claims_count}, $claim_count_1, 'Got the expected unchanged claim count from update claim');
407 is($late_or_missing_issues_1_2[0]->{status}, 3, 'Got the expected unchanged claim status from update claim');
410 is(C4::Serials::check_routing(), undef, 'test checking route');
411 is(C4::Serials::check_routing($subscriptionid), 0, 'There should not have any routing list for the subscription');
412 # TODO really test this check_routing subroutine
414 is(C4::Serials::addroutingmember(),undef, 'test adding route member');
417 # Unit tests for statuses management (Bug 11689)
418 $subscriptionid = NewSubscription(
419 undef, "", undef, undef, $budget_id, $biblionumber,
420 '2013-01-01', $frequency_id, undef, undef, undef,
421 undef, undef, undef, undef, undef, undef,
422 1, $notes,undef, '2013-01-01', undef, $pattern_id,
423 undef, undef, 0, $internalnotes, 0,
424 undef, undef, 0, undef, '2013-12-31', 0
427 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid );
428 is( $total_issues, 1, "NewSubscription created a first serial" );
429 is( @serials, 1, "GetSerials returns the serial" );
430 my $subscription = C4::Serials::GetSubscription($subscriptionid);
431 my $pattern = C4::Serials::Numberpattern::GetSubscriptionNumberpattern($subscription->{numberpattern});
432 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid );
433 my $publisheddate = output_pref({ dt => dt_from_string, dateformat => 'iso', dateonly => 1 });
434 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid );
435 $frequency = C4::Serials::Frequency::GetSubscriptionFrequency($subscription->{periodicity});
436 my $nextpublisheddate = C4::Serials::GetNextDate($subscription, $publisheddate, $frequency, 1);
437 my @statuses = qw( 2 2 3 3 3 3 3 4 4 41 42 43 44 5 );
440 for my $status ( @statuses ) {
441 my $serialseq = "No.".$counter;
442 my ( $expected_serial ) = GetSerials2( $subscriptionid, [1] );
443 C4::Serials::ModSerialStatus( $expected_serial->{serialid}, $serialseq, $publisheddate, $publisheddate, $publisheddate, $statuses[$counter], 'an useless note' );
446 # 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
447 my @serialsByStatus = C4::Serials::findSerialsByStatus(2,$subscriptionid);
448 is(@serialsByStatus,2,"findSerialsByStatus returns all serials with chosen status");
449 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid );
450 is( $total_issues, @statuses + 1, "GetSerials returns total_issues" );
451 my @arrived_missing = map { my $status = $_->{status}; ( grep { /^$status$/ } qw( 2 4 41 42 43 44 5 ) ) ? $_ : () } @serials;
452 my @others = map { my $status = $_->{status}; ( grep { /^$status$/ } qw( 2 4 41 42 43 44 5 ) ) ? () : $_ } @serials;
453 is( @arrived_missing, 5, "GetSerials returns 5 arrived/missing by default" );
454 is( @others, 6, "GetSerials returns all serials not arrived and not missing" );
456 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid, 10 );
457 is( $total_issues, @statuses + 1, "GetSerials returns total_issues" );
458 @arrived_missing = map { my $status = $_->{status}; ( grep { /^$status$/ } qw( 2 4 41 42 43 44 5 ) ) ? $_ : () } @serials;
459 @others = map { my $status = $_->{status}; ( grep { /^$status$/ } qw( 2 4 41 42 43 44 5 ) ) ? () : $_ } @serials;
460 is( @arrived_missing, 9, "GetSerials returns all arrived/missing if count given" );
461 is( @others, 6, "GetSerials returns all serials not arrived and not missing if count given" );
463 $subscription = C4::Serials::GetSubscription($subscriptionid); # Retrieve the updated subscription
466 for my $am ( @arrived_missing ) {
467 if ( grep {/^$am->{status}$/} qw( 4 41 42 43 44 ) ) {
468 push @serialseqs, $am->{serialseq}
469 } elsif ( grep {/^$am->{status}$/} qw( 5 ) ) {
470 push @serialseqs, 'not issued ' . $am->{serialseq};
473 is( $subscription->{missinglist}, join('; ', @serialseqs), "subscription missinglist is updated after ModSerialStatus" );
475 subtest "Do not generate an expected if one already exists" => sub {
477 my ($expected_serial) = GetSerials2( $subscriptionid, [1] );
479 #Find serialid for serial with status Expected
480 my $serialexpected = ( C4::Serials::findSerialsByStatus( 1, $subscriptionid ) )[0];
482 #delete serial with status Expected
483 C4::Serials::ModSerialStatus( $serialexpected->{serialid}, $serialexpected->{serialseq}, $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
484 @serialsByStatus = C4::Serials::findSerialsByStatus( 1, $subscriptionid );
485 is( @serialsByStatus, 1, "ModSerialStatus delete corectly serial expected and create another if not exist" );
487 # add 1 serial with status=Expected 1
488 C4::Serials::ModSerialStatus( $expected_serial->{serialid}, 'NO.20', $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
490 #Now we have two serials it have status expected
491 #put status delete for last serial
492 C4::Serials::ModSerialStatus( $serialexpected->{serialid}, $serialexpected->{serialseq}, $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
494 #try if create or not another serial with status is expected
495 @serialsByStatus = C4::Serials::findSerialsByStatus( 1, $subscriptionid );
496 is( @serialsByStatus, 1, "ModSerialStatus delete corectly serial expected and not create another if exists" );
499 subtest "PreserveSerialNotes preference" => sub {
501 my ($expected_serial) = GetSerials2( $subscriptionid, [1] );
503 t::lib::Mocks::mock_preference( 'PreserveSerialNotes', 1 );
505 C4::Serials::ModSerialStatus( $expected_serial->{serialid}, 'NO.20', $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
506 @serialsByStatus = C4::Serials::findSerialsByStatus( 1, $subscriptionid );
507 is( $serialsByStatus[0]->{note},$expected_serial->{note}, "note passed through if supposed to");
509 t::lib::Mocks::mock_preference( 'PreserveSerialNotes', 0 );
510 $expected_serial = $serialsByStatus[0];
511 C4::Serials::ModSerialStatus( $expected_serial->{serialid}, 'NO.20', $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
512 is( $serialsByStatus[0]->{note},$expected_serial->{note}, "note not passed through if not supposed to");
516 subtest "NewSubscription|ModSubscription" => sub {
518 my $subscriptionid = NewSubscription(
519 "", "", "", "", $budget_id, $biblionumber,
520 '2013-01-01', $frequency_id, "", "", "",
521 "", "", "", "", "", "",
522 1, $notes,"", '2013-01-01', "", $pattern_id,
523 "", "", 0, $internalnotes, 0,
524 "", "", 0, "", '2013-12-31', 0
526 ok($subscriptionid, "Sending empty string instead of undef to reflect use of the interface");
528 my $subscription = Koha::Subscriptions->find($subscriptionid);
529 my $serials = Koha::Serials->search({ subscriptionid => $subscriptionid });
530 is( $serials->count, 1, "NewSubscription created a first serial" );
532 my $biblio_2 = $builder->build_sample_biblio;
533 my $subscription_info = $subscription->unblessed;
534 $subscription_info->{biblionumber} = $biblio_2->biblionumber;
535 ModSubscription( @$subscription_info{qw(
536 librarian branchcode aqbooksellerid cost aqbudgetid startdate
537 periodicity firstacquidate irregularity numberpattern locale
538 numberlength weeklength monthlength lastvalue1 innerloop1 lastvalue2
539 innerloop2 lastvalue3 innerloop3 status biblionumber callnumber notes
540 letter manualhistory internalnotes serialsadditems staffdisplaycount
541 opacdisplaycount graceperiod location enddate subscriptionid
545 $serials = Koha::Serials->search({ subscriptionid => $subscriptionid });
546 is( $serials->count, 1, "Still only one serial" );
547 is( $serials->next->biblionumber, $biblio_2->biblionumber, 'ModSubscription should have updated serial.biblionumber');
550 subtest "_numeration" => sub {
554 my $s = C4::Serials::_numeration(0, 'monthname', 'cat');
556 $s = C4::Serials::_numeration(0, 'monthname', 'es');
558 $s = C4::Serials::_numeration(0, 'monthname', 'fr');
561 $s = C4::Serials::_numeration(0, 'monthabrv', 'cat');
563 $s = C4::Serials::_numeration(0, 'monthabrv', 'es');
564 like( $s, qr{^ene\.?} );
565 $s = C4::Serials::_numeration(0, 'monthabrv', 'fr');