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 => 52;
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 my $builder = t::lib::TestBuilder->new();
31 # This could/should be used for all untested methods
32 my @methods = ('updateClaim');
33 can_ok('C4::Serials', @methods);
35 $dbh->do(q|UPDATE marc_subfield_structure SET value_builder="callnumber.pl" where kohafield="items.itemcallnumber" and frameworkcode=''|);
37 my $bookseller = Koha::Acquisition::Bookseller->new(
40 address1 => "bookseller's address",
46 my ($biblionumber, $biblioitemnumber) = AddBiblio(MARC::Record->new, '');
48 my $bpid = AddBudgetPeriod({
49 budget_period_startdate => '2015-01-01',
50 budget_period_enddate => '2015-12-31',
51 budget_period_description => "budget desc"
54 my $budget_id = AddBudget({
55 budget_code => "ABCD",
56 budget_amount => "123.132",
57 budget_name => "Périodiques",
58 budget_notes => "This is a note",
59 budget_period_id => $bpid
62 my $frequency_id = AddSubscriptionFrequency({ description => "Test frequency 1" });
63 my $pattern_id = AddSubscriptionNumberpattern({
64 label => 'Test numberpattern 1',
65 description => 'Description for numberpattern 1',
66 numberingmethod => '{X}',
75 my $notes = "a\nnote\non\nseveral\nlines";
76 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,
85 undef, undef, undef, $ccode
89 my $subscriptioninformation = GetSubscription( $subscriptionid );
91 is( $subscriptioninformation->{notes}, $notes, 'NewSubscription should set notes' );
92 is( $subscriptioninformation->{internalnotes}, $internalnotes, 'NewSubscription should set internalnotes' );
93 is( $subscriptioninformation->{ccode}, $ccode, 'NewSubscription should set ccode' );
95 my $subscription_history = C4::Serials::GetSubscriptionHistoryFromSubscriptionId($subscriptionid);
96 is( $subscription_history->{opacnote}, undef, 'NewSubscription should not set subscriptionhistory opacnotes' );
97 is( $subscription_history->{librariannote}, undef, 'NewSubscription should not set subscriptionhistory librariannotes' );
99 my @subscriptions = SearchSubscriptions({string => $subscriptioninformation->{bibliotitle}, orderby => 'title' });
100 isa_ok( \@subscriptions, 'ARRAY' );
102 @subscriptions = SearchSubscriptions({ issn => $subscriptioninformation->{issn}, orderby => 'title' });
103 isa_ok( \@subscriptions, 'ARRAY' );
105 @subscriptions = SearchSubscriptions({ ean => $subscriptioninformation->{ean}, orderby => 'title' });
106 isa_ok( \@subscriptions, 'ARRAY' );
108 @subscriptions = SearchSubscriptions({ biblionumber => $subscriptioninformation->{bibnum}, orderby => 'title' });
109 isa_ok( \@subscriptions, 'ARRAY' );
111 my $frequency = GetSubscriptionFrequency($subscriptioninformation->{periodicity});
113 if (not $frequency->{unit}) {
114 $old_frequency = $frequency->{id};
115 $frequency->{unit} = "month";
116 $frequency->{unitsperissue} = 1;
117 $frequency->{issuesperunit} = 1;
118 $frequency->{description} = "Frequency created by t/db_dependant/Serials.t";
119 $subscriptioninformation->{periodicity} = AddSubscriptionFrequency($frequency);
120 $subscriptioninformation->{serialsadditems} = 1;
121 $subscriptioninformation->{ccode} = 'NFIC';
123 ModSubscription( @$subscriptioninformation{qw(
124 librarian branchcode aqbooksellerid cost aqbudgetid startdate
125 periodicity firstacquidate irregularity numberpattern locale
126 numberlength weeklength monthlength lastvalue1 innerloop1 lastvalue2
127 innerloop2 lastvalue3 innerloop3 status biblionumber callnumber notes
128 letter manualhistory internalnotes serialsadditems staffdisplaycount
129 opacdisplaycount graceperiod location enddate subscriptionid
130 skip_serialseq itemtype previousitemtype mana_id ccode
133 my $expirationdate = GetExpirationDate($subscriptionid) ;
134 ok( $expirationdate, "expiration date is not NULL" );
136 # Check ModSubscription has updated the ccode
137 my $subscriptioninformation2 = GetSubscription($subscriptionid);
138 is( $subscriptioninformation2->{ccode}, 'NFIC', 'ModSubscription should update ccode' );
140 ok(C4::Serials::GetSubscriptionHistoryFromSubscriptionId($subscriptionid), 'test getting history from sub-scription');
142 my ($serials_count, @serials) = GetSerials($subscriptionid);
143 ok($serials_count > 0, 'Subscription has at least one serial');
144 my $serial = $serials[0];
146 isa_ok(C4::Serials::GetSerialInformation($serial->{serialid}), 'HASH', 'test getting Serial Information');
148 subtest 'Values should not be erased on editing' => sub {
152 my $biblio = $builder->build_sample_biblio();
153 my $biblionumber = $biblio->biblionumber;
154 my ( $icn_tag, $icn_sf ) = GetMarcFromKohaField( 'items.itemcallnumber' );
155 my ( $it_tag, $it_sf ) = GetMarcFromKohaField( 'items.itype' );
157 my $itemtype = $builder->build( { source => 'Itemtype' } )->{itemtype};
158 my $itemcallnumber = 'XXXmy itemcallnumberXXX';
160 my $item_record = MARC::Record->new;
162 $item_record->append_fields(
163 MARC::Field->new( '080', '', '', "a" => "default" ),
166 $icn_sf => $itemcallnumber,
170 my ( undef, undef, $itemnumber ) = C4::Items::AddItemFromMarc( $item_record, $biblionumber );
171 my $serialid = C4::Serials::NewIssue( "serialseq", $subscriptionid, $biblionumber,
172 1, undef, undef, "publisheddatetext", "notes", "routingnotes" );
173 C4::Serials::AddItem2Serial( $serialid, $itemnumber );
174 my $serial_info = C4::Serials::GetSerialInformation($serialid);
175 my ($itemcallnumber_info) = grep { $_->{kohafield} eq 'items.itemcallnumber' }
176 @{ $serial_info->{items}[0]->{iteminformation} };
177 like( $itemcallnumber_info->{marc_value}, qr|value="$itemcallnumber"| );
180 # Delete created frequency
181 if ($old_frequency) {
182 my $freq_to_delete = $subscriptioninformation->{periodicity};
183 $subscriptioninformation->{periodicity} = $old_frequency;
185 ModSubscription( @$subscriptioninformation{qw(
186 librarian branchcode aqbooksellerid cost aqbudgetid startdate
187 periodicity firstacquidate irregularity numberpattern locale
188 numberlength weeklength monthlength lastvalue1 innerloop1 lastvalue2
189 innerloop2 lastvalue3 innerloop3 status biblionumber callnumber notes
190 letter manualhistory internalnotes serialsadditems staffdisplaycount
191 opacdisplaycount graceperiod location enddate subscriptionid
195 DelSubscriptionFrequency($freq_to_delete);
198 # Test calling subs without parameters
199 is(C4::Serials::AddItem2Serial(), undef, 'test adding item to serial');
200 is(C4::Serials::GetFullSubscription(), undef, 'test getting full subscription');
201 is(C4::Serials::PrepareSerialsData(), undef, 'test preparing serial data');
203 subtest 'GetSubscriptionsFromBiblionumber' => sub {
206 is( C4::Serials::GetSubscriptionsFromBiblionumber(),
207 undef, 'test getting subscriptions form biblio number' );
209 my $subscriptions = C4::Serials::GetSubscriptionsFromBiblionumber($biblionumber);
210 ModSubscriptionHistory( $subscriptions->[0]->{subscriptionid},
211 undef, undef, $notes, $notes, $notes );
213 $subscriptions = C4::Serials::GetSubscriptionsFromBiblionumber($biblionumber);
214 is( $subscriptions->[0]->{opacnote}, $notes,
215 'GetSubscriptionsFromBiblionumber should have returned the opacnote as it is in DB, ie. without br tags'
217 is( $subscriptions->[0]->{recievedlist}, $notes,
218 'GetSubscriptionsFromBiblionumber should have returned recievedlist as it is in DB, ie. without br tags'
220 is( $subscriptions->[0]->{missinglist}, $notes,
221 'GetSubscriptionsFromBiblionumber should have returned missinglist as it is in DB, ie. without br tags'
225 is(C4::Serials::GetSerials(), undef, 'test getting serials when you enter nothing');
226 is(C4::Serials::GetSerials2(), undef, 'test getting serials when you enter nothing');
228 is(C4::Serials::GetLatestSerials(), undef, 'test getting lastest serials');
230 is(C4::Serials::GetNextSeq(), undef, 'test getting next seq when you enter nothing');
232 is(C4::Serials::GetSeq(), undef, 'test getting seq when you enter nothing');
234 is(C4::Serials::CountSubscriptionFromBiblionumber(), undef, 'test counting subscription when nothing is entered');
236 is(C4::Serials::ModSubscriptionHistory(), undef, 'test modding subscription history');
238 is(C4::Serials::ModSerialStatus(),undef, 'test modding serials');
240 is(C4::Serials::findSerialsByStatus(), 0, 'test finding serial by status with no parameters');
242 is(C4::Serials::NewIssue(), undef, 'test getting 0 when nothing is entered');
244 is(C4::Serials::HasSubscriptionStrictlyExpired(), undef, 'test if the subscriptions has expired');
245 is(C4::Serials::HasSubscriptionExpired(), undef, 'test if the subscriptions has expired');
247 is(C4::Serials::GetLateOrMissingIssues(), undef, 'test getting last or missing issues');
249 subtest 'test_updateClaim' => sub {
252 my $today = output_pref({ dt => dt_from_string, dateonly => 1 });
253 # Given ... nothing much
255 my $result_0 = C4::Serials::updateClaim(undef);
256 is($result_0, undef, 'Got the expected undef from update claim with nothin');
258 # Given ... 3 serial. 2 of them updated.
259 my $claimdate_1 = dt_from_string('2001-01-13'); # arbitrary date some time in the past.
260 my $claim_count_1 = 5;
261 my $biblio = $builder->build_sample_biblio;
262 my $serial1 = $builder->build_object(
264 class => 'Koha::Serials',
266 serialseq => 'serialseq',
267 subscriptionid => $subscriptionid,
269 biblionumber => $biblio->biblionumber,
270 claimdate => $claimdate_1,
271 claims_count => $claim_count_1,
275 my $serial2 = $builder->build_object(
277 class => 'Koha::Serials',
279 serialseq => 'serialseq',
280 subscriptionid => $subscriptionid,
282 biblionumber => $biblio->biblionumber,
283 claimdate => $claimdate_1,
284 claims_count => $claim_count_1,
288 my $serial3 = $builder->build_object(
290 class => 'Koha::Serials',
292 serialseq => 'serialseq',
293 subscriptionid => $subscriptionid,
295 biblionumber => $biblio->biblionumber,
296 claimdate => $claimdate_1,
297 claims_count => $claim_count_1,
303 my $result_1 = C4::Serials::updateClaim([$serial1->serialid, $serial2->serialid]);
306 is($result_1, 2, 'Got the expected 2 from update claim with 2 serial ids');
308 my @late_or_missing_issues_1_0 = C4::Serials::GetLateOrMissingIssues(undef, $serial1->serialid);
309 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');
310 is($late_or_missing_issues_1_0[0]->{claims_count}, $claim_count_1+1, 'Got the expected first claim count from update claim');
311 is($late_or_missing_issues_1_0[0]->{status}, 7, 'Got the expected first claim status from update claim');
313 my @late_or_missing_issues_1_1 = C4::Serials::GetLateOrMissingIssues(undef, $serial2->serialid);
314 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');
315 is($late_or_missing_issues_1_1[0]->{claims_count}, $claim_count_1+1, 'Got the expected second claim count from update claim');
316 is($late_or_missing_issues_1_1[0]->{status}, 7, 'Got the expected second claim status from update claim');
318 my @late_or_missing_issues_1_2 = C4::Serials::GetLateOrMissingIssues(undef, $serial3->serialid);
319 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');
320 is($late_or_missing_issues_1_2[0]->{claims_count}, $claim_count_1, 'Got the expected unchanged claim count from update claim');
321 is($late_or_missing_issues_1_2[0]->{status}, 3, 'Got the expected unchanged claim status from update claim');
324 is(C4::Serials::check_routing(), undef, 'test checking route');
325 is(C4::Serials::check_routing($subscriptionid), 0, 'There should not have any routing list for the subscription');
326 # TODO really test this check_routing subroutine
328 is(C4::Serials::addroutingmember(),undef, 'test adding route member');
331 # Unit tests for statuses management (Bug 11689)
332 $subscriptionid = NewSubscription(
333 undef, "", undef, undef, $budget_id, $biblionumber,
334 '2013-01-01', $frequency_id, undef, undef, undef,
335 undef, undef, undef, undef, undef, undef,
336 1, $notes,undef, '2013-01-01', undef, $pattern_id,
337 undef, undef, 0, $internalnotes, 0,
338 undef, undef, 0, undef, '2013-12-31', 0
341 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid );
342 is( $total_issues, 1, "NewSubscription created a first serial" );
343 is( @serials, 1, "GetSerials returns the serial" );
344 my $subscription = C4::Serials::GetSubscription($subscriptionid);
345 my $pattern = C4::Serials::Numberpattern::GetSubscriptionNumberpattern($subscription->{numberpattern});
346 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid );
347 my $publisheddate = output_pref({ dt => dt_from_string, dateformat => 'iso', dateonly => 1 });
348 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid );
349 $frequency = C4::Serials::Frequency::GetSubscriptionFrequency($subscription->{periodicity});
350 my $nextpublisheddate = C4::Serials::GetNextDate($subscription, $publisheddate, $frequency, 1);
351 my @statuses = qw( 2 2 3 3 3 3 3 4 4 41 42 43 44 5 );
354 for my $status ( @statuses ) {
355 my $serialseq = "No.".$counter;
356 my ( $expected_serial ) = GetSerials2( $subscriptionid, [1] );
357 C4::Serials::ModSerialStatus( $expected_serial->{serialid}, $serialseq, $publisheddate, $publisheddate, $publisheddate, $statuses[$counter], 'an useless note' );
360 # 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
361 my @serialsByStatus = C4::Serials::findSerialsByStatus(2,$subscriptionid);
362 is(@serialsByStatus,2,"findSerialsByStatus returns all serials with chosen status");
363 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid );
364 is( $total_issues, @statuses + 1, "GetSerials returns total_issues" );
365 my @arrived_missing = map { my $status = $_->{status}; ( grep { /^$status$/ } qw( 2 4 41 42 43 44 5 ) ) ? $_ : () } @serials;
366 my @others = map { my $status = $_->{status}; ( grep { /^$status$/ } qw( 2 4 41 42 43 44 5 ) ) ? () : $_ } @serials;
367 is( @arrived_missing, 5, "GetSerials returns 5 arrived/missing by default" );
368 is( @others, 6, "GetSerials returns all serials not arrived and not missing" );
370 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid, 10 );
371 is( $total_issues, @statuses + 1, "GetSerials returns total_issues" );
372 @arrived_missing = map { my $status = $_->{status}; ( grep { /^$status$/ } qw( 2 4 41 42 43 44 5 ) ) ? $_ : () } @serials;
373 @others = map { my $status = $_->{status}; ( grep { /^$status$/ } qw( 2 4 41 42 43 44 5 ) ) ? () : $_ } @serials;
374 is( @arrived_missing, 9, "GetSerials returns all arrived/missing if count given" );
375 is( @others, 6, "GetSerials returns all serials not arrived and not missing if count given" );
377 $subscription = C4::Serials::GetSubscription($subscriptionid); # Retrieve the updated subscription
380 for my $am ( @arrived_missing ) {
381 if ( grep {/^$am->{status}$/} qw( 4 41 42 43 44 ) ) {
382 push @serialseqs, $am->{serialseq}
383 } elsif ( grep {/^$am->{status}$/} qw( 5 ) ) {
384 push @serialseqs, 'not issued ' . $am->{serialseq};
387 is( $subscription->{missinglist}, join('; ', @serialseqs), "subscription missinglist is updated after ModSerialStatus" );
389 subtest "Do not generate an expected if one already exists" => sub {
391 my ($expected_serial) = GetSerials2( $subscriptionid, [1] );
393 #Find serialid for serial with status Expected
394 my $serialexpected = ( C4::Serials::findSerialsByStatus( 1, $subscriptionid ) )[0];
396 #delete serial with status Expected
397 C4::Serials::ModSerialStatus( $serialexpected->{serialid}, $serialexpected->{serialseq}, $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
398 @serialsByStatus = C4::Serials::findSerialsByStatus( 1, $subscriptionid );
399 is( @serialsByStatus, 1, "ModSerialStatus delete corectly serial expected and create another if not exist" );
401 # add 1 serial with status=Expected 1
402 C4::Serials::ModSerialStatus( $expected_serial->{serialid}, 'NO.20', $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
404 #Now we have two serials it have status expected
405 #put status delete for last serial
406 C4::Serials::ModSerialStatus( $serialexpected->{serialid}, $serialexpected->{serialseq}, $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
408 #try if create or not another serial with status is expected
409 @serialsByStatus = C4::Serials::findSerialsByStatus( 1, $subscriptionid );
410 is( @serialsByStatus, 1, "ModSerialStatus delete corectly serial expected and not create another if exists" );
413 subtest "PreserveSerialNotes preference" => sub {
415 my ($expected_serial) = GetSerials2( $subscriptionid, [1] );
417 t::lib::Mocks::mock_preference( 'PreserveSerialNotes', 1 );
419 C4::Serials::ModSerialStatus( $expected_serial->{serialid}, 'NO.20', $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
420 @serialsByStatus = C4::Serials::findSerialsByStatus( 1, $subscriptionid );
421 is( $serialsByStatus[0]->{note},$expected_serial->{note}, "note passed through if supposed to");
423 t::lib::Mocks::mock_preference( 'PreserveSerialNotes', 0 );
424 $expected_serial = $serialsByStatus[0];
425 C4::Serials::ModSerialStatus( $expected_serial->{serialid}, 'NO.20', $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
426 is( $serialsByStatus[0]->{note},$expected_serial->{note}, "note not passed through if not supposed to");
430 subtest "NewSubscription|ModSubscription" => sub {
432 my $subscriptionid = NewSubscription(
433 "", "", "", "", $budget_id, $biblionumber,
434 '2013-01-01', $frequency_id, "", "", "",
435 "", "", "", "", "", "",
436 1, $notes,"", '2013-01-01', "", $pattern_id,
437 "", "", 0, $internalnotes, 0,
438 "", "", 0, "", '2013-12-31', 0
440 ok($subscriptionid, "Sending empty string instead of undef to reflect use of the interface");
442 my $subscription = Koha::Subscriptions->find($subscriptionid);
443 my $serials = Koha::Serials->search({ subscriptionid => $subscriptionid });
444 is( $serials->count, 1, "NewSubscription created a first serial" );
446 my $biblio_2 = $builder->build_sample_biblio;
447 my $subscription_info = $subscription->unblessed;
448 $subscription_info->{biblionumber} = $biblio_2->biblionumber;
449 ModSubscription( @$subscription_info{qw(
450 librarian branchcode aqbooksellerid cost aqbudgetid startdate
451 periodicity firstacquidate irregularity numberpattern locale
452 numberlength weeklength monthlength lastvalue1 innerloop1 lastvalue2
453 innerloop2 lastvalue3 innerloop3 status biblionumber callnumber notes
454 letter manualhistory internalnotes serialsadditems staffdisplaycount
455 opacdisplaycount graceperiod location enddate subscriptionid
459 $serials = Koha::Serials->search({ subscriptionid => $subscriptionid });
460 is( $serials->count, 1, "Still only one serial" );
461 is( $serials->next->biblionumber, $biblio_2->biblionumber, 'ModSubscription should have updated serial.biblionumber');
464 subtest "_numeration" => sub {
468 my $s = C4::Serials::_numeration(0, 'monthname', 'cat');
470 $s = C4::Serials::_numeration(0, 'monthname', 'es');
472 $s = C4::Serials::_numeration(0, 'monthname', 'fr');
475 $s = C4::Serials::_numeration(0, 'monthabrv', 'cat');
477 $s = C4::Serials::_numeration(0, 'monthabrv', 'es');
478 like( $s, qr{^ene\.?} );
479 $s = C4::Serials::_numeration(0, 'monthabrv', 'fr');