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 => 52;
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 my $builder = t::lib::TestBuilder->new();
36 # This could/should be used for all untested methods
37 my @methods = ('updateClaim');
38 can_ok('C4::Serials', @methods);
40 $dbh->do(q|UPDATE marc_subfield_structure SET value_builder="callnumber.pl" where kohafield="items.itemcallnumber" and frameworkcode=''|);
42 my $bookseller = Koha::Acquisition::Bookseller->new(
45 address1 => "bookseller's address",
51 my ($biblionumber, $biblioitemnumber) = AddBiblio(MARC::Record->new, '');
53 my $bpid = AddBudgetPeriod({
54 budget_period_startdate => '2015-01-01',
55 budget_period_enddate => '2015-12-31',
56 budget_period_description => "budget desc"
59 my $budget_id = AddBudget({
60 budget_code => "ABCD",
61 budget_amount => "123.132",
62 budget_name => "Périodiques",
63 budget_notes => "This is a note",
64 budget_period_id => $bpid
67 my $frequency_id = AddSubscriptionFrequency({ description => "Test frequency 1" });
68 my $pattern_id = AddSubscriptionNumberpattern({
69 label => 'Test numberpattern 1',
70 description => 'Description for numberpattern 1',
71 numberingmethod => '{X}',
80 my $notes = "a\nnote\non\nseveral\nlines";
81 my $internalnotes = 'intnotes';
83 my $subscriptionid = NewSubscription(
84 undef, "", undef, undef, $budget_id, $biblionumber,
85 '2013-01-01', $frequency_id, undef, undef, undef,
86 undef, undef, undef, undef, undef, undef,
87 1, $notes, ,undef, '2013-01-01', undef, $pattern_id,
88 undef, undef, 0, $internalnotes, 0,
89 undef, undef, 0, undef, '2013-12-31', 0,
90 undef, undef, undef, $ccode
94 my $subscriptioninformation = GetSubscription( $subscriptionid );
96 is( $subscriptioninformation->{notes}, $notes, 'NewSubscription should set notes' );
97 is( $subscriptioninformation->{internalnotes}, $internalnotes, 'NewSubscription should set internalnotes' );
98 is( $subscriptioninformation->{ccode}, $ccode, 'NewSubscription should set ccode' );
100 my $subscription_history = C4::Serials::GetSubscriptionHistoryFromSubscriptionId($subscriptionid);
101 is( $subscription_history->{opacnote}, undef, 'NewSubscription should not set subscriptionhistory opacnotes' );
102 is( $subscription_history->{librariannote}, undef, 'NewSubscription should not set subscriptionhistory librariannotes' );
104 my @subscriptions = SearchSubscriptions({string => $subscriptioninformation->{bibliotitle}, orderby => 'title' });
105 isa_ok( \@subscriptions, 'ARRAY' );
107 @subscriptions = SearchSubscriptions({ issn => $subscriptioninformation->{issn}, orderby => 'title' });
108 isa_ok( \@subscriptions, 'ARRAY' );
110 @subscriptions = SearchSubscriptions({ ean => $subscriptioninformation->{ean}, orderby => 'title' });
111 isa_ok( \@subscriptions, 'ARRAY' );
113 @subscriptions = SearchSubscriptions({ biblionumber => $subscriptioninformation->{bibnum}, orderby => 'title' });
114 isa_ok( \@subscriptions, 'ARRAY' );
116 my $frequency = GetSubscriptionFrequency($subscriptioninformation->{periodicity});
118 if (not $frequency->{unit}) {
119 $old_frequency = $frequency->{id};
120 $frequency->{unit} = "month";
121 $frequency->{unitsperissue} = 1;
122 $frequency->{issuesperunit} = 1;
123 $frequency->{description} = "Frequency created by t/db_dependant/Serials.t";
124 $subscriptioninformation->{periodicity} = AddSubscriptionFrequency($frequency);
125 $subscriptioninformation->{serialsadditems} = 1;
126 $subscriptioninformation->{ccode} = 'NFIC';
128 ModSubscription( @$subscriptioninformation{qw(
129 librarian branchcode aqbooksellerid cost aqbudgetid startdate
130 periodicity firstacquidate irregularity numberpattern locale
131 numberlength weeklength monthlength lastvalue1 innerloop1 lastvalue2
132 innerloop2 lastvalue3 innerloop3 status biblionumber callnumber notes
133 letter manualhistory internalnotes serialsadditems staffdisplaycount
134 opacdisplaycount graceperiod location enddate subscriptionid
135 skip_serialseq itemtype previousitemtype mana_id ccode
138 my $expirationdate = GetExpirationDate($subscriptionid) ;
139 ok( $expirationdate, "expiration date is not NULL" );
141 # Check ModSubscription has updated the ccode
142 my $subscriptioninformation2 = GetSubscription($subscriptionid);
143 is( $subscriptioninformation2->{ccode}, 'NFIC', 'ModSubscription should update ccode' );
145 ok(C4::Serials::GetSubscriptionHistoryFromSubscriptionId($subscriptionid), 'test getting history from sub-scription');
147 my ($serials_count, @serials) = GetSerials($subscriptionid);
148 ok($serials_count > 0, 'Subscription has at least one serial');
149 my $serial = $serials[0];
151 isa_ok(C4::Serials::GetSerialInformation($serial->{serialid}), 'HASH', 'test getting Serial Information');
153 subtest 'Values should not be erased on editing' => sub {
157 my $biblio = $builder->build_sample_biblio();
158 my $biblionumber = $biblio->biblionumber;
159 my ( $icn_tag, $icn_sf ) = GetMarcFromKohaField( 'items.itemcallnumber' );
160 my ( $it_tag, $it_sf ) = GetMarcFromKohaField( 'items.itype' );
162 my $itemtype = $builder->build( { source => 'Itemtype' } )->{itemtype};
163 my $itemcallnumber = 'XXXmy itemcallnumberXXX';
165 my $item_record = MARC::Record->new;
167 $item_record->append_fields(
168 MARC::Field->new( '080', '', '', "a" => "default" ),
171 $icn_sf => $itemcallnumber,
175 my ( undef, undef, $itemnumber ) = C4::Items::AddItemFromMarc( $item_record, $biblionumber );
176 my $serialid = C4::Serials::NewIssue( "serialseq", $subscriptionid, $biblionumber,
177 1, undef, undef, "publisheddatetext", "notes", "routingnotes" );
178 C4::Serials::AddItem2Serial( $serialid, $itemnumber );
179 my $serial_info = C4::Serials::GetSerialInformation($serialid);
180 my ($itemcallnumber_info) = grep { $_->{kohafield} eq 'items.itemcallnumber' }
181 @{ $serial_info->{items}[0]->{iteminformation} };
182 like( $itemcallnumber_info->{marc_value}, qr|value="$itemcallnumber"| );
185 # Delete created frequency
186 if ($old_frequency) {
187 my $freq_to_delete = $subscriptioninformation->{periodicity};
188 $subscriptioninformation->{periodicity} = $old_frequency;
190 ModSubscription( @$subscriptioninformation{qw(
191 librarian branchcode aqbooksellerid cost aqbudgetid startdate
192 periodicity firstacquidate irregularity numberpattern locale
193 numberlength weeklength monthlength lastvalue1 innerloop1 lastvalue2
194 innerloop2 lastvalue3 innerloop3 status biblionumber callnumber notes
195 letter manualhistory internalnotes serialsadditems staffdisplaycount
196 opacdisplaycount graceperiod location enddate subscriptionid
200 DelSubscriptionFrequency($freq_to_delete);
203 # Test calling subs without parameters
204 is(C4::Serials::AddItem2Serial(), undef, 'test adding item to serial');
205 is(C4::Serials::GetFullSubscription(), undef, 'test getting full subscription');
206 is(C4::Serials::PrepareSerialsData(), undef, 'test preparing serial data');
208 subtest 'GetSubscriptionsFromBiblionumber' => sub {
211 is( C4::Serials::GetSubscriptionsFromBiblionumber(),
212 undef, 'test getting subscriptions form biblio number' );
214 my $subscriptions = C4::Serials::GetSubscriptionsFromBiblionumber($biblionumber);
215 ModSubscriptionHistory( $subscriptions->[0]->{subscriptionid},
216 undef, undef, $notes, $notes, $notes );
218 $subscriptions = C4::Serials::GetSubscriptionsFromBiblionumber($biblionumber);
219 is( $subscriptions->[0]->{opacnote}, $notes,
220 'GetSubscriptionsFromBiblionumber should have returned the opacnote as it is in DB, ie. without br tags'
222 is( $subscriptions->[0]->{recievedlist}, $notes,
223 'GetSubscriptionsFromBiblionumber should have returned recievedlist as it is in DB, ie. without br tags'
225 is( $subscriptions->[0]->{missinglist}, $notes,
226 'GetSubscriptionsFromBiblionumber should have returned missinglist as it is in DB, ie. without br tags'
230 is(C4::Serials::GetSerials(), undef, 'test getting serials when you enter nothing');
231 is(C4::Serials::GetSerials2(), undef, 'test getting serials when you enter nothing');
233 is(C4::Serials::GetLatestSerials(), undef, 'test getting lastest serials');
235 is(C4::Serials::GetNextSeq(), undef, 'test getting next seq when you enter nothing');
237 is(C4::Serials::GetSeq(), undef, 'test getting seq when you enter nothing');
239 is(C4::Serials::CountSubscriptionFromBiblionumber(), undef, 'test counting subscription when nothing is entered');
241 is(C4::Serials::ModSubscriptionHistory(), undef, 'test modding subscription history');
243 is(C4::Serials::ModSerialStatus(),undef, 'test modding serials');
245 is(C4::Serials::findSerialsByStatus(), 0, 'test finding serial by status with no parameters');
247 is(C4::Serials::NewIssue(), undef, 'test getting 0 when nothing is entered');
249 is(C4::Serials::HasSubscriptionStrictlyExpired(), undef, 'test if the subscriptions has expired');
250 is(C4::Serials::HasSubscriptionExpired(), undef, 'test if the subscriptions has expired');
252 is(C4::Serials::GetLateOrMissingIssues(), undef, 'test getting last or missing issues');
254 subtest 'test_updateClaim' => sub {
257 my $today = output_pref({ dt => dt_from_string, dateonly => 1 });
258 # Given ... nothing much
260 my $result_0 = C4::Serials::updateClaim(undef);
261 is($result_0, undef, 'Got the expected undef from update claim with nothin');
263 # Given ... 3 serial. 2 of them updated.
264 my $claimdate_1 = dt_from_string('2001-01-13'); # arbitrary date some time in the past.
265 my $claim_count_1 = 5;
266 my $biblio = $builder->build_sample_biblio;
267 my $serial1 = $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 $serial2 = $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,
293 my $serial3 = $builder->build_object(
295 class => 'Koha::Serials',
297 serialseq => 'serialseq',
298 subscriptionid => $subscriptionid,
300 biblionumber => $biblio->biblionumber,
301 claimdate => $claimdate_1,
302 claims_count => $claim_count_1,
308 my $result_1 = C4::Serials::updateClaim([$serial1->serialid, $serial2->serialid]);
311 is($result_1, 2, 'Got the expected 2 from update claim with 2 serial ids');
313 my @late_or_missing_issues_1_0 = C4::Serials::GetLateOrMissingIssues(undef, $serial1->serialid);
314 is($late_or_missing_issues_1_0[0]->{claimdate}, $today, 'Got the expected first different claim date from update claim');
315 is($late_or_missing_issues_1_0[0]->{claims_count}, $claim_count_1+1, 'Got the expected first claim count from update claim');
316 is($late_or_missing_issues_1_0[0]->{status}, 7, 'Got the expected first claim status from update claim');
318 my @late_or_missing_issues_1_1 = C4::Serials::GetLateOrMissingIssues(undef, $serial2->serialid);
319 is($late_or_missing_issues_1_1[0]->{claimdate}, $today, 'Got the expected second different claim date from update claim');
320 is($late_or_missing_issues_1_1[0]->{claims_count}, $claim_count_1+1, 'Got the expected second claim count from update claim');
321 is($late_or_missing_issues_1_1[0]->{status}, 7, 'Got the expected second claim status from update claim');
323 my @late_or_missing_issues_1_2 = C4::Serials::GetLateOrMissingIssues(undef, $serial3->serialid);
324 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');
325 is($late_or_missing_issues_1_2[0]->{claims_count}, $claim_count_1, 'Got the expected unchanged claim count from update claim');
326 is($late_or_missing_issues_1_2[0]->{status}, 3, 'Got the expected unchanged claim status from update claim');
329 is(C4::Serials::check_routing(), undef, 'test checking route');
330 is(C4::Serials::check_routing($subscriptionid), 0, 'There should not have any routing list for the subscription');
331 # TODO really test this check_routing subroutine
333 is(C4::Serials::addroutingmember(),undef, 'test adding route member');
336 # Unit tests for statuses management (Bug 11689)
337 $subscriptionid = NewSubscription(
338 undef, "", undef, undef, $budget_id, $biblionumber,
339 '2013-01-01', $frequency_id, undef, undef, undef,
340 undef, undef, undef, undef, undef, undef,
341 1, $notes,undef, '2013-01-01', undef, $pattern_id,
342 undef, undef, 0, $internalnotes, 0,
343 undef, undef, 0, undef, '2013-12-31', 0
346 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid );
347 is( $total_issues, 1, "NewSubscription created a first serial" );
348 is( @serials, 1, "GetSerials returns the serial" );
349 my $subscription = C4::Serials::GetSubscription($subscriptionid);
350 my $pattern = C4::Serials::Numberpattern::GetSubscriptionNumberpattern($subscription->{numberpattern});
351 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid );
352 my $publisheddate = output_pref({ dt => dt_from_string, dateformat => 'iso', dateonly => 1 });
353 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid );
354 $frequency = C4::Serials::Frequency::GetSubscriptionFrequency($subscription->{periodicity});
355 my $nextpublisheddate = C4::Serials::GetNextDate($subscription, $publisheddate, $frequency, 1);
356 my @statuses = qw( 2 2 3 3 3 3 3 4 4 41 42 43 44 5 );
359 for my $status ( @statuses ) {
360 my $serialseq = "No.".$counter;
361 my ( $expected_serial ) = GetSerials2( $subscriptionid, [1] );
362 C4::Serials::ModSerialStatus( $expected_serial->{serialid}, $serialseq, $publisheddate, $publisheddate, $publisheddate, $statuses[$counter], 'an useless note' );
365 # 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
366 my @serialsByStatus = C4::Serials::findSerialsByStatus(2,$subscriptionid);
367 is(@serialsByStatus,2,"findSerialsByStatus returns all serials with chosen status");
368 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid );
369 is( $total_issues, @statuses + 1, "GetSerials returns total_issues" );
370 my @arrived_missing = map { my $status = $_->{status}; ( grep { /^$status$/ } qw( 2 4 41 42 43 44 5 ) ) ? $_ : () } @serials;
371 my @others = map { my $status = $_->{status}; ( grep { /^$status$/ } qw( 2 4 41 42 43 44 5 ) ) ? () : $_ } @serials;
372 is( @arrived_missing, 5, "GetSerials returns 5 arrived/missing by default" );
373 is( @others, 6, "GetSerials returns all serials not arrived and not missing" );
375 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid, 10 );
376 is( $total_issues, @statuses + 1, "GetSerials returns total_issues" );
377 @arrived_missing = map { my $status = $_->{status}; ( grep { /^$status$/ } qw( 2 4 41 42 43 44 5 ) ) ? $_ : () } @serials;
378 @others = map { my $status = $_->{status}; ( grep { /^$status$/ } qw( 2 4 41 42 43 44 5 ) ) ? () : $_ } @serials;
379 is( @arrived_missing, 9, "GetSerials returns all arrived/missing if count given" );
380 is( @others, 6, "GetSerials returns all serials not arrived and not missing if count given" );
382 $subscription = C4::Serials::GetSubscription($subscriptionid); # Retrieve the updated subscription
385 for my $am ( @arrived_missing ) {
386 if ( grep {/^$am->{status}$/} qw( 4 41 42 43 44 ) ) {
387 push @serialseqs, $am->{serialseq}
388 } elsif ( grep {/^$am->{status}$/} qw( 5 ) ) {
389 push @serialseqs, 'not issued ' . $am->{serialseq};
392 is( $subscription->{missinglist}, join('; ', @serialseqs), "subscription missinglist is updated after ModSerialStatus" );
394 subtest "Do not generate an expected if one already exists" => sub {
396 my ($expected_serial) = GetSerials2( $subscriptionid, [1] );
398 #Find serialid for serial with status Expected
399 my $serialexpected = ( C4::Serials::findSerialsByStatus( 1, $subscriptionid ) )[0];
401 #delete serial with status Expected
402 C4::Serials::ModSerialStatus( $serialexpected->{serialid}, $serialexpected->{serialseq}, $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
403 @serialsByStatus = C4::Serials::findSerialsByStatus( 1, $subscriptionid );
404 is( @serialsByStatus, 1, "ModSerialStatus delete corectly serial expected and create another if not exist" );
406 # add 1 serial with status=Expected 1
407 C4::Serials::ModSerialStatus( $expected_serial->{serialid}, 'NO.20', $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
409 #Now we have two serials it have status expected
410 #put status delete for last serial
411 C4::Serials::ModSerialStatus( $serialexpected->{serialid}, $serialexpected->{serialseq}, $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
413 #try if create or not another serial with status is expected
414 @serialsByStatus = C4::Serials::findSerialsByStatus( 1, $subscriptionid );
415 is( @serialsByStatus, 1, "ModSerialStatus delete corectly serial expected and not create another if exists" );
418 subtest "PreserveSerialNotes preference" => sub {
420 my ($expected_serial) = GetSerials2( $subscriptionid, [1] );
422 t::lib::Mocks::mock_preference( 'PreserveSerialNotes', 1 );
424 C4::Serials::ModSerialStatus( $expected_serial->{serialid}, 'NO.20', $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
425 @serialsByStatus = C4::Serials::findSerialsByStatus( 1, $subscriptionid );
426 is( $serialsByStatus[0]->{note},$expected_serial->{note}, "note passed through if supposed to");
428 t::lib::Mocks::mock_preference( 'PreserveSerialNotes', 0 );
429 $expected_serial = $serialsByStatus[0];
430 C4::Serials::ModSerialStatus( $expected_serial->{serialid}, 'NO.20', $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
431 is( $serialsByStatus[0]->{note},$expected_serial->{note}, "note not passed through if not supposed to");
435 subtest "NewSubscription|ModSubscription" => sub {
437 my $subscriptionid = NewSubscription(
438 "", "", "", "", $budget_id, $biblionumber,
439 '2013-01-01', $frequency_id, "", "", "",
440 "", "", "", "", "", "",
441 1, $notes,"", '2013-01-01', "", $pattern_id,
442 "", "", 0, $internalnotes, 0,
443 "", "", 0, "", '2013-12-31', 0
445 ok($subscriptionid, "Sending empty string instead of undef to reflect use of the interface");
447 my $subscription = Koha::Subscriptions->find($subscriptionid);
448 my $serials = Koha::Serials->search({ subscriptionid => $subscriptionid });
449 is( $serials->count, 1, "NewSubscription created a first serial" );
451 my $biblio_2 = $builder->build_sample_biblio;
452 my $subscription_info = $subscription->unblessed;
453 $subscription_info->{biblionumber} = $biblio_2->biblionumber;
454 ModSubscription( @$subscription_info{qw(
455 librarian branchcode aqbooksellerid cost aqbudgetid startdate
456 periodicity firstacquidate irregularity numberpattern locale
457 numberlength weeklength monthlength lastvalue1 innerloop1 lastvalue2
458 innerloop2 lastvalue3 innerloop3 status biblionumber callnumber notes
459 letter manualhistory internalnotes serialsadditems staffdisplaycount
460 opacdisplaycount graceperiod location enddate subscriptionid
464 $serials = Koha::Serials->search({ subscriptionid => $subscriptionid });
465 is( $serials->count, 1, "Still only one serial" );
466 is( $serials->next->biblionumber, $biblio_2->biblionumber, 'ModSubscription should have updated serial.biblionumber');
469 subtest "_numeration" => sub {
473 my $s = C4::Serials::_numeration(0, 'monthname', 'cat');
475 $s = C4::Serials::_numeration(0, 'monthname', 'es');
477 $s = C4::Serials::_numeration(0, 'monthname', 'fr');
480 $s = C4::Serials::_numeration(0, 'monthabrv', 'cat');
482 $s = C4::Serials::_numeration(0, 'monthabrv', 'es');
483 like( $s, qr{^ene\.?} );
484 $s = C4::Serials::_numeration(0, 'monthabrv', 'fr');