Bug 17835: Add an additional LEFT JOIN condition using DBIx::Class
[koha.git] / t / db_dependent / Serials.t
1 #!/usr/bin/perl
2 #
3 # This Koha test module is a stub!
4 # Add more tests here!!!
5
6 use Modern::Perl;
7 use YAML;
8
9 use CGI qw ( -utf8 );
10 use C4::Serials;
11 use C4::Serials::Frequency;
12 use C4::Serials::Numberpattern;
13 use C4::Debug;
14 use C4::Biblio;
15 use C4::Budgets;
16 use C4::Items;
17 use Koha::DateUtils;
18 use Koha::Acquisition::Booksellers;
19 use t::lib::Mocks;
20 use Test::More tests => 49;
21
22 BEGIN {
23     use_ok('C4::Serials');
24 }
25
26 my $dbh = C4::Context->dbh;
27
28 # Start transaction
29 $dbh->{AutoCommit} = 0;
30 $dbh->{RaiseError} = 1;
31
32 # This could/should be used for all untested methods
33 my @methods = ('updateClaim');
34 can_ok('C4::Serials', @methods);
35
36 $dbh->do(q|UPDATE marc_subfield_structure SET value_builder="callnumber.pl" where kohafield="items.itemcallnumber" and frameworkcode=''|);
37
38 my $bookseller = Koha::Acquisition::Bookseller->new(
39     {
40         name => "my vendor",
41         address1 => "bookseller's address",
42         phone => "0123456",
43         active => 1
44     }
45 );
46
47 my ($biblionumber, $biblioitemnumber) = AddBiblio(MARC::Record->new, '');
48
49 my $budgetid;
50 my $bpid = AddBudgetPeriod({
51     budget_period_startdate   => '01-01-2015',
52     budget_period_enddate     => '31-12-2015',
53     budget_period_description => "budget desc"
54 });
55
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
62 });
63
64 my $frequency_id = AddSubscriptionFrequency({ description => "Test frequency 1" });
65 my $pattern_id = AddSubscriptionNumberpattern({
66     label => 'Test numberpattern 1',
67     numberingmethod => '{X}',
68     label1 => q{},
69     add1 => 1,
70     every1 => 1,
71     every1 => 1,
72     numbering1 => 1,
73     whenmorethan1 => 1,
74 });
75
76 my $notes = 'notes';
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
85 );
86
87 my $subscriptioninformation = GetSubscription( $subscriptionid );
88
89 is( $subscriptioninformation->{notes}, $notes, 'NewSubscription should set notes' );
90 is( $subscriptioninformation->{internalnotes}, $internalnotes, 'NewSubscription should set internalnotes' );
91
92 my $subscription_history = C4::Serials::GetSubscriptionHistoryFromSubscriptionId($subscriptionid);
93 is( $subscription_history->{opacnote}, '', 'NewSubscription should not set subscriptionhistory opacnotes' );
94 is( $subscription_history->{librariannote}, '', 'NewSubscription should not set subscriptionhistory librariannotes' );
95
96 my @subscriptions = SearchSubscriptions({string => $subscriptioninformation->{bibliotitle}, orderby => 'title' });
97 isa_ok( \@subscriptions, 'ARRAY' );
98
99 @subscriptions = SearchSubscriptions({ issn => $subscriptioninformation->{issn}, orderby => 'title' });
100 isa_ok( \@subscriptions, 'ARRAY' );
101
102 @subscriptions = SearchSubscriptions({ ean => $subscriptioninformation->{ean}, orderby => 'title' });
103 isa_ok( \@subscriptions, 'ARRAY' );
104
105 @subscriptions = SearchSubscriptions({ biblionumber => $subscriptioninformation->{bibnum}, orderby => 'title' });
106 isa_ok( \@subscriptions, 'ARRAY' );
107
108 my $frequency = GetSubscriptionFrequency($subscriptioninformation->{periodicity});
109 my $old_frequency;
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;
118
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
126         skip_serialseq
127     )} );
128 }
129 my $expirationdate = GetExpirationDate($subscriptionid) ;
130 ok( $expirationdate, "expiration date is not NULL" );
131
132 ok(C4::Serials::GetSubscriptionHistoryFromSubscriptionId($subscriptionid), 'test getting history from sub-scription');
133
134 my ($serials_count, @serials) = GetSerials($subscriptionid);
135 ok($serials_count > 0, 'Subscription has at least one serial');
136 my $serial = $serials[0];
137
138 ok(C4::Serials::GetSerialStatusFromSerialId($serial->{serialid}), 'test getting Serial Status From Serial Id');
139
140 isa_ok(C4::Serials::GetSerialInformation($serial->{serialid}), 'HASH', 'test getting Serial Information');
141
142 subtest 'Values should not be erased on editing' => sub {
143     plan tests => 1;
144     ( $biblionumber, $biblioitemnumber ) = get_biblio();
145     my ( $icn_tag, $icn_sf ) = GetMarcFromKohaField( 'items.itemcallnumber', '' );
146     my $item_record    = new MARC::Record;
147     my $itemcallnumber = 'XXXmy itemcallnumberXXX';
148     $item_record->append_fields( MARC::Field->new( '080', '', '', "a" => "default" ), MARC::Field->new( $icn_tag, '', '', $icn_sf => $itemcallnumber ), );
149     my ( undef, undef, $itemnumber ) = C4::Items::AddItemFromMarc( $item_record, $biblionumber );
150     my $serialid = C4::Serials::NewIssue( "serialseq", $subscriptionid, $biblionumber, 1, undef, undef, "publisheddatetext", "notes" );
151     C4::Serials::AddItem2Serial( $serialid, $itemnumber );
152     my $serial_info = C4::Serials::GetSerialInformation($serialid);
153     my ($itemcallnumber_info) = grep { $_->{kohafield} eq 'items.itemcallnumber' } @{ $serial_info->{items}[0]->{iteminformation} };
154     like( $itemcallnumber_info->{marc_value}, qr|value="$itemcallnumber"| );
155 };
156
157 # Delete created frequency
158 if ($old_frequency) {
159     my $freq_to_delete = $subscriptioninformation->{periodicity};
160     $subscriptioninformation->{periodicity} = $old_frequency;
161
162     ModSubscription( @$subscriptioninformation{qw(
163         librarian branchcode aqbooksellerid cost aqbudgetid startdate
164         periodicity firstacquidate irregularity numberpattern locale
165         numberlength weeklength monthlength lastvalue1 innerloop1 lastvalue2
166         innerloop2 lastvalue3 innerloop3 status biblionumber callnumber notes
167         letter manualhistory internalnotes serialsadditems staffdisplaycount
168         opacdisplaycount graceperiod location enddate subscriptionid
169         skip_serialseq
170     )} );
171
172     DelSubscriptionFrequency($freq_to_delete);
173 }
174
175 # Test calling subs without parameters
176 is(C4::Serials::AddItem2Serial(), undef, 'test adding item to serial');
177 is(C4::Serials::GetFullSubscription(), undef, 'test getting full subscription');
178 is(C4::Serials::PrepareSerialsData(), undef, 'test preparing serial data');
179 is(C4::Serials::GetSubscriptionsFromBiblionumber(), undef, 'test getting subscriptions form biblio number');
180
181 is(C4::Serials::GetSerials(), undef, 'test getting serials when you enter nothing');
182 is(C4::Serials::GetSerials2(), undef, 'test getting serials when you enter nothing');
183
184 is(C4::Serials::GetLatestSerials(), undef, 'test getting lastest serials');
185
186 is(C4::Serials::GetDistributedTo(), undef, 'test getting distributed when nothing is entered');
187
188 is(C4::Serials::GetNextSeq(), undef, 'test getting next seq when you enter nothing');
189
190 is(C4::Serials::GetSeq(), undef, 'test getting seq when you enter nothing');
191
192 is(C4::Serials::CountSubscriptionFromBiblionumber(), undef, 'test counting subscription when nothing is entered');
193
194 is(C4::Serials::ModSubscriptionHistory(), undef, 'test modding subscription history');
195
196 is(C4::Serials::ModSerialStatus(),undef, 'test modding serials');
197
198 is(C4::Serials::findSerialsByStatus(), 0, 'test finding serial by status with no parameters');
199
200 is(C4::Serials::NewIssue(), undef, 'test getting 0 when nothing is entered');
201
202 is(C4::Serials::HasSubscriptionStrictlyExpired(), undef, 'test if the subscriptions has expired');
203 is(C4::Serials::HasSubscriptionExpired(), undef, 'test if the subscriptions has expired');
204
205 is(C4::Serials::GetLateOrMissingIssues(), undef, 'test getting last or missing issues');
206
207 subtest 'test_updateClaim' => sub {
208     plan tests => 11;
209
210     my $today = output_pref({ dt => dt_from_string, dateonly => 1 });
211     # Given ... nothing much
212     # When ... Then ...
213     my $result_0 = C4::Serials::updateClaim(undef);
214     is($result_0, undef, 'Got the expected undef from update claim with nothin');
215
216     # Given ... 3 serial. 2 of them updated.
217     my $serialids_1   = [90980, 90981];
218     my $claimdate_1   = dt_from_string('2001-01-13'); # arbitrary date some time in the past.
219     my $claim_count_1 = 5;
220     Koha::Serial->new( { serialid => $serialids_1->[0], serialseq => 'serialseq', subscriptionid => $subscriptionid, status => 3,
221                          biblionumber => 12345, claimdate => $claimdate_1, claims_count => $claim_count_1, } )->store();
222     Koha::Serial->new( { serialid => $serialids_1->[1], serialseq => 'serialseq', subscriptionid => $subscriptionid, status => 3,
223                          biblionumber => 12345, claimdate => $claimdate_1, claims_count => $claim_count_1,  } )->store();
224     Koha::Serial->new( { serialid => 90982, serialseq => 'serialseq', subscriptionid => $subscriptionid, status => 3,
225                          biblionumber => 12345, claimdate => $claimdate_1, claims_count => $claim_count_1,  } )->store();
226
227     # When ...
228     my $result_1 = C4::Serials::updateClaim($serialids_1);
229
230     # Then ...
231     is($result_1, 2, 'Got the expected 2 from update claim with 2 serial ids');
232
233     my @late_or_missing_issues_1_0 = C4::Serials::GetLateOrMissingIssues(undef, $serialids_1->[0]);
234     is($late_or_missing_issues_1_0[0]->{claimdate}, $today, 'Got the expected first different claim date from update claim');
235     is($late_or_missing_issues_1_0[0]->{claims_count}, $claim_count_1+1, 'Got the expected first claim count from update claim');
236     is($late_or_missing_issues_1_0[0]->{status}, 7, 'Got the expected first claim status from update claim');
237
238     my @late_or_missing_issues_1_1 = C4::Serials::GetLateOrMissingIssues(undef, $serialids_1->[1]);
239     is($late_or_missing_issues_1_1[0]->{claimdate}, $today, 'Got the expected second different claim date from update claim');
240     is($late_or_missing_issues_1_1[0]->{claims_count}, $claim_count_1+1, 'Got the expected second claim count from update claim');
241     is($late_or_missing_issues_1_1[0]->{status}, 7, 'Got the expected second claim status from update claim');
242
243     my @late_or_missing_issues_1_2 = C4::Serials::GetLateOrMissingIssues(undef, 90982);
244     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');
245     is($late_or_missing_issues_1_2[0]->{claims_count}, $claim_count_1, 'Got the expected unchanged claim count from update claim');
246     is($late_or_missing_issues_1_2[0]->{status}, 3, 'Got the expected unchanged claim status from update claim');
247 };
248
249 is(C4::Serials::getsupplierbyserialid(),undef, 'test getting supplier idea');
250
251 is(C4::Serials::check_routing(), undef, 'test checking route');
252
253 is(C4::Serials::addroutingmember(),undef, 'test adding route member');
254
255
256 # Unit tests for statuses management (Bug 11689)
257 $subscriptionid = NewSubscription(
258     undef,      "",     undef, undef, $budget_id, $biblionumber,
259     '2013-01-01', $frequency_id, undef, undef,  undef,
260     undef,      undef,  undef, undef, undef, undef,
261     1,          $notes,undef, '2013-01-01', undef, $pattern_id,
262     undef,       undef,  0,    $internalnotes,  0,
263     undef, undef, 0,          undef,         '2013-12-31', 0
264 );
265 my $total_issues;
266 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid );
267 is( $total_issues, 1, "NewSubscription created a first serial" );
268 is( @serials, 1, "GetSerials returns the serial" );
269 my $subscription = C4::Serials::GetSubscription($subscriptionid);
270 my $pattern = C4::Serials::Numberpattern::GetSubscriptionNumberpattern($subscription->{numberpattern});
271 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid );
272 my $publisheddate = output_pref({ dt => dt_from_string, dateformat => 'iso', dateonly => 1 });
273 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid );
274 my $nextpublisheddate = C4::Serials::GetNextDate($subscription, $publisheddate, 1);
275 my @statuses = qw( 2 2 3 3 3 3 3 4 4 41 42 43 44 5 );
276 # Add 14 serials
277 my $counter = 0;
278 for my $status ( @statuses ) {
279     my $serialseq = "No.".$counter;
280     my ( $expected_serial ) = GetSerials2( $subscriptionid, [1] );
281     C4::Serials::ModSerialStatus( $expected_serial->{serialid}, $serialseq, $publisheddate, $publisheddate, $publisheddate, $statuses[$counter], 'an useless note' );
282     $counter++;
283 }
284 # 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
285 my @serialsByStatus = C4::Serials::findSerialsByStatus(2,$subscriptionid);
286 is(@serialsByStatus,2,"findSerialsByStatus returns all serials with chosen status");
287 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid );
288 is( $total_issues, @statuses + 1, "GetSerials returns total_issues" );
289 my @arrived_missing = map { my $status = $_->{status}; ( grep { /^$status$/ } qw( 2 4 41 42 43 44 5 ) ) ? $_ : () } @serials;
290 my @others = map { my $status = $_->{status}; ( grep { /^$status$/ } qw( 2 4 41 42 43 44 5 ) ) ? () : $_ } @serials;
291 is( @arrived_missing, 5, "GetSerials returns 5 arrived/missing by default" );
292 is( @others, 6, "GetSerials returns all serials not arrived and not missing" );
293
294 ( $total_issues, @serials ) = C4::Serials::GetSerials( $subscriptionid, 10 );
295 is( $total_issues, @statuses + 1, "GetSerials returns total_issues" );
296 @arrived_missing = map { my $status = $_->{status}; ( grep { /^$status$/ } qw( 2 4 41 42 43 44 5 ) ) ? $_ : () } @serials;
297 @others = map { my $status = $_->{status}; ( grep { /^$status$/ } qw( 2 4 41 42 43 44 5 ) ) ? () : $_ } @serials;
298 is( @arrived_missing, 9, "GetSerials returns all arrived/missing if count given" );
299 is( @others, 6, "GetSerials returns all serials not arrived and not missing if count given" );
300
301 $subscription = C4::Serials::GetSubscription($subscriptionid); # Retrieve the updated subscription
302
303 my @serialseqs;
304 for my $am ( @arrived_missing ) {
305     if ( grep {/^$am->{status}$/} qw( 4 41 42 43 44 ) ) {
306         push @serialseqs, $am->{serialseq}
307     } elsif ( grep {/^$am->{status}$/} qw( 5 ) ) {
308         push @serialseqs, 'not issued ' . $am->{serialseq};
309     }
310 }
311 is( $subscription->{missinglist}, join('; ', @serialseqs), "subscription missinglist is updated after ModSerialStatus" );
312
313 subtest "Do not generate an expected if one already exists" => sub {
314     plan tests => 2;
315     my ($expected_serial) = GetSerials2( $subscriptionid, [1] );
316
317     #Find serialid for serial with status Expected
318     my $serialexpected = ( C4::Serials::findSerialsByStatus( 1, $subscriptionid ) )[0];
319
320     #delete serial with status Expected
321     C4::Serials::ModSerialStatus( $serialexpected->{serialid}, $serialexpected->{serialseq}, $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
322     @serialsByStatus = C4::Serials::findSerialsByStatus( 1, $subscriptionid );
323     is( @serialsByStatus, 1, "ModSerialStatus delete corectly serial expected and create another if not exist" );
324
325     # add 1 serial with status=Expected 1
326     C4::Serials::ModSerialStatus( $expected_serial->{serialid}, 'NO.20', $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
327
328     #Now we have two serials it have status expected
329     #put status delete for last serial
330     C4::Serials::ModSerialStatus( $serialexpected->{serialid}, $serialexpected->{serialseq}, $publisheddate, $publisheddate, $publisheddate, '1', 'an useless note' );
331
332     #try if create or not another serial with status is expected
333     @serialsByStatus = C4::Serials::findSerialsByStatus( 1, $subscriptionid );
334     is( @serialsByStatus, 1, "ModSerialStatus delete corectly serial expected and not create another if exists" );
335 };
336
337 $dbh->rollback;
338
339 sub get_biblio {
340     my $bib = MARC::Record->new();
341     $bib->append_fields(
342         MARC::Field->new('100', ' ', ' ', a => 'Moffat, Steven'),
343         MARC::Field->new('245', ' ', ' ', a => 'Silence in the library'),
344     );
345     my ($bibnum, $bibitemnum) = AddBiblio($bib, '');
346     return ($bibnum, $bibitemnum);
347 }