Bug 18309: Add UNIMARC field 214 and its subfields
[koha.git] / t / db_dependent / Items / GetItemsForInventory.t
blob56ca417e921ddc09b736718f78ab6000ae72fc55
1 #!/usr/bin/perl
3 # This file is part of Koha.
5 # Copyright (c) 2015 Mark Tompsett
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
20 use Modern::Perl;
22 use Test::More tests => 9;
23 use t::lib::TestBuilder;
25 use List::MoreUtils qw( any none );
27 use C4::Biblio qw(AddBiblio);
28 use C4::Reserves;
29 use C4::ClassSource;
30 use Koha::AuthorisedValues;
31 use Koha::Biblios;
32 use Koha::Database;
33 use MARC::Record;
35 BEGIN {
36 use_ok('C4::Context');
37 use_ok('C4::Items');
38 use_ok('C4::Biblio');
39 use_ok('C4::Koha');
42 can_ok('C4::Items','GetItemsForInventory');
44 my $schema = Koha::Database->new->schema;
45 my $builder = t::lib::TestBuilder->new;
47 subtest 'Old version is unchanged' => sub {
49 plan tests => 1;
51 $schema->storage->txn_begin;
53 my $dbh = $schema->storage->dbh;
55 my ($oldResults, $oldCount) = OldWay($dbh);
56 my ($newResults, $newCount) = GetItemsForInventory;
58 is_deeply($newResults,$oldResults,"Inventory results unchanged.");
60 $schema->storage->txn_rollback;
63 subtest 'Skip items with waiting holds' => sub {
65 plan tests => 7;
67 $schema->storage->txn_begin;
69 my $library = $builder->build_object( { class => 'Koha::Libraries' } );
70 my $itemtype
71 = $builder->build_object( { class => 'Koha::ItemTypes', value => { rentalcharge => 0 } } );
72 my $patron_1 = $builder->build_object(
73 { class => 'Koha::Patrons', value => { branchcode => $library->id } } );
74 my $patron_2 = $builder->build_object(
75 { class => 'Koha::Patrons', value => { branchcode => $library->id } } );
78 my $title_1 = 'Title 1, ';
79 my $title_2 = 'Title 2, bizzarre one so doesn\'t already exist';
81 my $biblio_1 = $builder->build_sample_biblio({ itemtype => $itemtype->itemtype, title => $title_1 });
82 my $biblio_2 = $builder->build_sample_biblio({ itemtype => $itemtype->itemtype, title => $title_2 });
84 my ( $items_1, $first_items_count ) = GetItemsForInventory();
85 is( scalar @{$items_1}, $first_items_count, 'Results and count match' );
87 # Add two items, so we don't depend on existing data
88 my $item_1 = $builder->build_object(
89 { class => 'Koha::Items',
90 value => {
91 biblionumber => $biblio_1->biblionumber,
92 biblioitemnumber => $biblio_1->biblioitem->biblioitemnumber,
93 homebranch => $library->id,
94 holdingbranch => $library->id,
95 itype => $itemtype->itemtype,
96 reserves => undef
101 my $item_2 = $builder->build_object(
102 { class => 'Koha::Items',
103 value => {
104 biblionumber => $biblio_2->biblionumber,
105 biblioitemnumber => $biblio_2->biblioitem->biblioitemnumber,
106 homebranch => $library->id,
107 holdingbranch => $library->id,
108 itype => $itemtype->itemtype,
109 reserves => undef
114 my ( $items_2, $second_items_count ) = GetItemsForInventory();
115 is( scalar @{$items_2}, $second_items_count, 'Results and count match' );
116 is( $first_items_count + 2, $second_items_count, 'Two items added, count makes sense' );
118 # Add 2 waiting holds
119 C4::Reserves::AddReserve( $library->branchcode, $patron_1->borrowernumber,
120 $item_1->biblionumber, '', 1, undef, undef, '', "title for fee",
121 $item_1->itemnumber, 'W' );
122 C4::Reserves::AddReserve( $library->branchcode, $patron_1->borrowernumber,
123 $item_2->biblionumber, '', 1, undef, undef, '', "title for fee",
124 $item_2->itemnumber, undef );
125 C4::Reserves::AddReserve( $library->branchcode, $patron_2->borrowernumber,
126 $item_2->biblionumber, '', 2, undef, undef, '', "title for fee",
127 $item_2->itemnumber, undef );
129 my ( $new_items, $new_items_count ) = GetItemsForInventory( { ignore_waiting_holds => 1 } );
130 is( $new_items_count, $first_items_count + 1, 'Item on hold skipped, count makes sense' );
131 ok( (any { $_->{title} eq $title_2 } @{$new_items}),
132 'Item on hold skipped, the other one we added is present' );
133 ok( (none { $_->{title} eq $title_1 } @{$new_items}),
134 'Item on hold skipped, no one matches' );
135 is( scalar(@$new_items), $new_items_count, 'total and number of items is the same');
137 $schema->storage->txn_rollback;
140 subtest 'Verify results with OldWay' => sub {
141 $schema->storage->txn_begin;
142 plan tests => 1;
144 my ($oldResults, $oldCount) = OldWay();
145 my ($newResults, $newCount) = GetItemsForInventory();
146 is_deeply($newResults,$oldResults,"Inventory results unchanged.");
147 $schema->storage->txn_rollback;
150 subtest 'Use cn_sort rather than callnumber to determine correct location' => sub {
151 $schema->storage->txn_begin;
152 plan tests => 1;
154 my $builder = t::lib::TestBuilder->new;
156 my $class_rule = $builder->build({
157 source => 'ClassSortRule',
158 value => { sort_routine => "LCC" }
160 my $class_source = $builder->build({
161 source => 'ClassSource',
162 value => {
163 class_sort_rule => $class_rule->{class_sort_rule},
167 #Find if we have any items in our test range before we start
168 my( undef, $pre_item_count) = GetItemsForInventory({
169 maxlocation => 'GT100',
170 minlocation => 'GT90',
171 class_source => $class_source->{cn_source},
174 my $item_1 = $builder->build({
175 source => 'Item',
176 value => {
177 itemcallnumber => 'GT95',
178 cn_sort => GetClassSort($class_source->{cn_source},undef,'GT95'),
182 my( undef, $item_count) = GetItemsForInventory({
183 maxlocation => 'GT100',
184 minlocation => 'GT90',
185 class_source => $class_source->{cn_source},
187 is($item_count,$pre_item_count + 1,"We should return GT95 as between GT90 and GT100");
188 $schema->storage->txn_rollback;
192 sub OldWay { # FIXME Do we really still need so much code to check results ??
193 my $ldbh = C4::Context->dbh;
195 my $minlocation = '';
196 my $maxlocation = '';
197 my $location = '';
198 my $itemtype = '';
199 my $ignoreissued = '';
200 my $datelastseen = '';
201 my $branchcode = '';
202 my $branch = '';
203 my $offset = '';
204 my $size = '';
205 my $statushash = '';
207 my ( @bind_params, @where_strings );
209 my $select_columns = q{
210 SELECT items.itemnumber, barcode, itemcallnumber, title, author, biblio.biblionumber, biblio.frameworkcode, datelastseen, homebranch, location, notforloan, damaged, itemlost, withdrawn, stocknumber
212 my $select_count = q{SELECT COUNT(*)};
213 my $query = q{
214 FROM items
215 LEFT JOIN biblio ON items.biblionumber = biblio.biblionumber
216 LEFT JOIN biblioitems on items.biblionumber = biblioitems.biblionumber
218 if ($statushash){
219 for my $authvfield (keys %$statushash){
220 if ( scalar @{$statushash->{$authvfield}} > 0 ){
221 my $joinedvals = join ',', @{$statushash->{$authvfield}};
222 push @where_strings, "$authvfield in (" . $joinedvals . ")";
227 if ($minlocation) {
228 push @where_strings, 'itemcallnumber >= ?';
229 push @bind_params, $minlocation;
232 if ($maxlocation) {
233 push @where_strings, 'itemcallnumber <= ?';
234 push @bind_params, $maxlocation;
237 if ($datelastseen) {
238 $datelastseen = output_pref({ str => $datelastseen, dateformat => 'iso', dateonly => 1 });
239 push @where_strings, '(datelastseen < ? OR datelastseen IS NULL)';
240 push @bind_params, $datelastseen;
243 if ( $location ) {
244 push @where_strings, 'items.location = ?';
245 push @bind_params, $location;
248 if ( $branchcode ) {
249 if($branch eq "homebranch"){
250 push @where_strings, 'items.homebranch = ?';
251 }else{
252 push @where_strings, 'items.holdingbranch = ?';
254 push @bind_params, $branchcode;
257 if ( $itemtype ) {
258 push @where_strings, 'biblioitems.itemtype = ?';
259 push @bind_params, $itemtype;
262 if ( $ignoreissued) {
263 $query .= "LEFT JOIN issues ON items.itemnumber = issues.itemnumber ";
264 push @where_strings, 'issues.date_due IS NULL';
267 if ( @where_strings ) {
268 $query .= 'WHERE ';
269 $query .= join ' AND ', @where_strings;
271 my $count_query = $select_count . $query;
272 $query .= ' ORDER BY items.cn_sort, itemcallnumber, title';
273 $query .= " LIMIT $offset, $size" if ($offset and $size);
274 $query = $select_columns . $query;
275 my $sth = $ldbh->prepare($query);
276 $sth->execute( @bind_params );
278 my @results = ();
279 my $tmpresults = $sth->fetchall_arrayref({});
280 $sth = $ldbh->prepare( $count_query );
281 $sth->execute( @bind_params );
282 my ($iTotalRecords) = $sth->fetchrow_array();
284 my $marc_field_mapping;
285 foreach my $row (@$tmpresults) {
287 # Auth values
288 foreach my $field (sort keys %$row) {
289 # If the koha field is mapped to a marc field
290 my ($f, $sf) = C4::Biblio::GetMarcFromKohaField( "items.$field" );
291 if (defined($f) and defined($sf)) {
292 # We replace the code with it's description
293 my $avs;
294 if ( exists $marc_field_mapping->{$row->{frameworkcode}}{$f}{$sf} ) {
295 $avs = $marc_field_mapping->{$row->{frameworkcode}}{$f}{$sf};
296 } else {
297 $avs = Koha::AuthorisedValues->search_by_marc_field({ frameworkcode => $row->{frameworkcode}, tagfield => $f, tagsubfield => $sf, });
298 $marc_field_mapping->{$row->{frameworkcode}}{$f}{$sf} = $avs->unblessed;
300 my $authvals = { map { $_->{authorised_value} => $_->{lib} } @{ $marc_field_mapping->{$row->{frameworkcode}}{$f}{$sf} } };
301 $row->{$field} = $authvals->{$row->{$field}} if defined $authvals && defined $row->{$field} && defined $authvals->{$row->{$field}};
304 push @results, $row;
307 return (\@results, $iTotalRecords);