View | Details | Raw Unified | Return to bug 7684
Collapse All | Expand All

(-)a/C4/Items.pm (-13 / +26 lines)
Lines 970-978 sub GetLostItems { Link Here
970
970
971
=head2 GetItemsForInventory
971
=head2 GetItemsForInventory
972
972
973
  $itemlist = GetItemsForInventory($minlocation, $maxlocation, 
973
($itemlist, $iTotalRecords)  = GetItemsForInventory($minlocation, $maxlocation, $location, $itemtype, $ignoreissued, $datelastseen, $branchcode, $offset, $size, $statushash);
974
                 $location, $itemtype $datelastseen, $branch, 
975
                 $offset, $size, $statushash);
976
974
977
Retrieve a list of title/authors/barcode/callnumber, for biblio inventory.
975
Retrieve a list of title/authors/barcode/callnumber, for biblio inventory.
978
976
Lines 985-990 the datelastseen can be used to specify that you want to see items not seen sinc Link Here
985
offset & size can be used to retrieve only a part of the whole listing (defaut behaviour)
983
offset & size can be used to retrieve only a part of the whole listing (defaut behaviour)
986
$statushash requires a hashref that has the authorized values fieldname (intems.notforloan, etc...) as keys, and an arrayref of statuscodes we are searching for as values.
984
$statushash requires a hashref that has the authorized values fieldname (intems.notforloan, etc...) as keys, and an arrayref of statuscodes we are searching for as values.
987
985
986
$iTotalRecords is the number of rows that would have been returned without the $offset, $size limit clause
987
988
=cut
988
=cut
989
989
990
sub GetItemsForInventory {
990
sub GetItemsForInventory {
Lines 993-999 sub GetItemsForInventory { Link Here
993
    my ( @bind_params, @where_strings );
993
    my ( @bind_params, @where_strings );
994
994
995
    my $query = <<'END_SQL';
995
    my $query = <<'END_SQL';
996
SELECT items.itemnumber, barcode, itemcallnumber, title, author, biblio.biblionumber, datelastseen
996
SELECT SQL_CALC_FOUND_ROWS items.itemnumber, barcode, itemcallnumber, title, author, biblio.biblionumber, biblio.frameworkcode, datelastseen, homebranch, location, notforloan, damaged, itemlost, stocknumber
997
FROM items
997
FROM items
998
  LEFT JOIN biblio ON items.biblionumber = biblio.biblionumber
998
  LEFT JOIN biblio ON items.biblionumber = biblio.biblionumber
999
  LEFT JOIN biblioitems on items.biblionumber = biblioitems.biblionumber
999
  LEFT JOIN biblioitems on items.biblionumber = biblioitems.biblionumber
Lines 1036-1042 END_SQL Link Here
1036
        }
1036
        }
1037
        push @bind_params, $branchcode;
1037
        push @bind_params, $branchcode;
1038
    }
1038
    }
1039
    
1039
1040
    if ( $itemtype ) {
1040
    if ( $itemtype ) {
1041
        push @where_strings, 'biblioitems.itemtype = ?';
1041
        push @where_strings, 'biblioitems.itemtype = ?';
1042
        push @bind_params, $itemtype;
1042
        push @bind_params, $itemtype;
Lines 1052-1071 END_SQL Link Here
1052
        $query .= join ' AND ', @where_strings;
1052
        $query .= join ' AND ', @where_strings;
1053
    }
1053
    }
1054
    $query .= ' ORDER BY items.cn_sort, itemcallnumber, title';
1054
    $query .= ' ORDER BY items.cn_sort, itemcallnumber, title';
1055
    $query .= " LIMIT $offset, $size" if ($offset and $size);
1055
    my $sth = $dbh->prepare($query);
1056
    my $sth = $dbh->prepare($query);
1056
    $sth->execute( @bind_params );
1057
    $sth->execute( @bind_params );
1057
1058
1058
    my @results;
1059
    my @results;
1059
    $size--;
1060
    my $tmpresults = $sth->fetchall_arrayref({});
1060
    while ( my $row = $sth->fetchrow_hashref ) {
1061
    $sth = $dbh->prepare("SELECT FOUND_ROWS()");
1061
        $offset-- if ($offset);
1062
    $sth->execute();
1062
        $row->{datelastseen}=format_date($row->{datelastseen});
1063
    my ($iTotalRecords) = $sth->fetchrow_array();
1063
        if ( ( !$offset ) && $size ) {
1064
1064
            push @results, $row;
1065
    foreach my $row (@$tmpresults) {
1065
            $size--;
1066
        $row->{datelastseen} = format_date( $row->{datelastseen} );
1067
1068
        # Auth values
1069
        foreach (keys %$row) {
1070
            # If the koha field is mapped to a marc field
1071
            my ($f, $sf) = GetMarcFromKohaField("items.$_", $row->{'frameworkcode'});
1072
            if ($f and $sf) {
1073
                # We replace the code with it's description
1074
                my $authvals = C4::Koha::GetKohaAuthorisedValuesFromField($f, $sf, $row->{'frameworkcode'});
1075
                $row->{$_} = $authvals->{$row->{$_}} if defined $authvals->{$row->{$_}};
1076
            }
1066
        }
1077
        }
1078
        push @results, $row;
1067
    }
1079
    }
1068
    return \@results;
1080
1081
    return (\@results, $iTotalRecords);
1069
}
1082
}
1070
1083
1071
=head2 GetItemsCount
1084
=head2 GetItemsCount
(-)a/C4/Templates.pm (-1 / +1 lines)
Lines 328-334 sub getlanguage { Link Here
328
    my $lang;
328
    my $lang;
329
329
330
    # cookie
330
    # cookie
331
    if ( $query->cookie('KohaOpacLanguage') ) {
331
    if ($query and $query->cookie('KohaOpacLanguage') ) {
332
        $lang = $query->cookie('KohaOpacLanguage');
332
        $lang = $query->cookie('KohaOpacLanguage');
333
        $lang =~ s/[^a-zA-Z_-]*//; # sanitize cookie
333
        $lang =~ s/[^a-zA-Z_-]*//; # sanitize cookie
334
    }
334
    }
(-)a/koha-tmpl/intranet-tmpl/prog/en/columns.def (+1 lines)
Lines 138-140 biblioitems.place Place of publication Link Here
138
biblioitems.lccn	LCCN
138
biblioitems.lccn	LCCN
139
biblioitems.marcxml	MARC blob
139
biblioitems.marcxml	MARC blob
140
biblioitems.url	URL
140
biblioitems.url	URL
141
biblioitems.title	Title
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/inventory.tt (-108 / +134 lines)
Lines 1-30 Link Here
1
[% INCLUDE 'doc-head-open.inc' %]
1
[% INCLUDE 'doc-head-open.inc' %]
2
<title>Koha &rsaquo; Tools &rsaquo; Inventory</title>
2
<title>Koha &rsaquo; Tools &rsaquo; Inventory</title>
3
[% INCLUDE 'doc-head-close.inc' %]
3
[% INCLUDE 'doc-head-close.inc' %]
4
<link rel="stylesheet" type="text/css" href="[% themelang %]/css/datatables.css" />
5
<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.dataTables.min.js"></script>
6
<script type="text/javascript" src="[% themelang %]/js/datatables.js"></script>
4
[% INCLUDE 'calendar.inc' %]
7
[% INCLUDE 'calendar.inc' %]
5
<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.checkboxes.min.js"></script>
8
<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.checkboxes.min.js"></script>
6
<script type="text/javascript">
9
<script type="text/javascript">
7
//<![CDATA[
10
//<![CDATA[
8
$(document).ready(function(){
11
$(document).ready(function(){
9
	$(".checkall").click(function(){
12
10
	        $(".checkboxed").checkCheckboxes();
13
        inventorydt = $('#inventoryt').dataTable($.extend(true, {}, dataTablesDefaults, {
11
	        return false;
14
            'sPaginationType': 'full_numbers',
12
		});
15
            "aoColumnDefs": [ { "bSortable": false, "aTargets": [ 0 ] } ]
13
	$(".clearall").click(function(){
16
        } ));
14
	        $(".checkboxed").unCheckCheckboxes();
17
15
	        return false;
18
16
	    });
19
    $("#continuewithoutmarkingbutton").click(function(){
20
                inventorydt.fnPageChange( 'next' );
21
            return false;
22
        });
23
24
        $("#markseenandcontinuebutton").click(function(){
25
            var param = '';
26
            $("input:checked").each(function() {
27
                param += "|" + $(this).attr('name');
28
            });
29
            $.post('/cgi-bin/koha/tools/ajax-inventory.pl', { seen: param });
30
            inventorydt.fnPageChange( 'next' );
31
            return false;
32
        });
33
34
        $("#markseenandquit").click(function(){
35
            var param = '';
36
            $("input:checked").each(function() {
37
                param += "|" + $(this).attr('name');
38
            });
39
            $.ajax({
40
              type: 'POST',
41
              url: '/cgi-bin/koha/tools/ajax-inventory.pl',
42
              data: { seen: param},
43
              async: false
44
            });
45
            document.location.href = '/cgi-bin/koha/tools/inventory.pl';
46
            return false;
47
        });
48
49
50
51
    $(".checkall").click(function(){
52
            $(".checkboxed").checkCheckboxes();
53
            return false;
54
        });
55
    $(".clearall").click(function(){
56
            $(".checkboxed").unCheckCheckboxes();
57
            return false;
58
        });
17
[% IF ( offset ) %]$("#markseen").before("<input type=\"submit\" value=\"&lt;&lt; " + _("Mark seen and continue") + "\" id=\"markback\" /> ");[% END %]
59
[% IF ( offset ) %]$("#markseen").before("<input type=\"submit\" value=\"&lt;&lt; " + _("Mark seen and continue") + "\" id=\"markback\" /> ");[% END %]
18
[% IF ( nextoffset ) %]$("#markseen").after(" <input type=\"submit\" id=\"marknext\" value=\"" + _("Mark seen and continue") + " &gt;&gt;\" />");[% END %]
60
[% IF ( nextoffset ) %]$("#markseen").after(" <input type=\"submit\" id=\"marknext\" value=\"" + _("Mark seen and continue") + " &gt;&gt;\" />");[% END %]
19
	$("#markback").click(function(){
61
    $("#markback").click(function(){
20
		$(".checkboxed").find("input").filter("[name=offset]").attr("value","[% prevoffset %]");
62
        $(".checkboxed").find("input").filter("[name=offset]").attr("value","[% prevoffset %]");
21
		return true;
63
        return true;
22
	});
64
    });
23
	$("#marknext").click(function(){
65
    $("#marknext").click(function(){
24
		$(".checkboxed").find("input").filter("[name=offset]").attr("value","[% nextoffset %]");
66
        $(".checkboxed").find("input").filter("[name=offset]").attr("value","[% nextoffset %]");
25
		return true;
67
        return true;
26
	});
68
    });
27
	});
69
    });
28
//]]>
70
//]]>
29
</script>
71
</script>
30
</head>
72
</head>
Lines 32-65 $(document).ready(function(){ Link Here
32
[% INCLUDE 'header.inc' %]
74
[% INCLUDE 'header.inc' %]
33
[% INCLUDE 'cat-search.inc' %]
75
[% INCLUDE 'cat-search.inc' %]
34
76
35
<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/tools/tools-home.pl">Tools</a> &rsaquo; [% IF ( loop ) %]<a href="/cgi-bin/koha/tools/inventory.pl">Inventory</a> &rsaquo; Results[% ELSE %]Inventory[% END %]</div>
77
<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/tools/tools-home.pl">Tools</a> &rsaquo; [% IF (loop) %]<a href="/cgi-bin/koha/tools/inventory.pl">Inventory</a> &rsaquo; Results[% ELSE %]Inventory[% END %]</div>
36
78
37
<div id="doc3" class="yui-t2">
79
<div id="doc3" class="yui-t2">
38
   
80
39
   <div id="bd">
81
   <div id="bd">
40
	<div id="yui-main">
82
    <div id="yui-main">
41
	<div class="yui-b">
83
    <div class="yui-b">
42
    <h1>Inventory/Stocktaking</h1>
84
    <h1>Inventory/Stocktaking</h1>
43
    [% IF ( Number ) %]<div class="dialog message">[% Number %] items modified : datelastseen set to [% date %]</div>[% END %]
85
    [% IF (moddatecount) %]<div class="dialog message">[% moddatecount %] items modified : datelastseen set to [% date %]</div>[% END %]
44
    [% IF ( errorfile ) %]<div class="dialog alert">[% errorfile %] can't be opened</div>[% END %]
86
    [% IF (errorfile) %]<div class="dialog alert">[% errorfile %] can't be opened</div>[% END %]
45
    [% FOREACH errorloo IN errorloop %]
87
    [% FOREACH error IN errorloop %]
46
        <div class="dialog alert">
88
        <div class="dialog alert">
47
            [% errorloo.barcode %]
89
            [% error.barcode %]
48
            [% IF ( errorloo.ERR_BARCODE ) %]: barcode not found[% END %]
90
            [% IF (error.ERR_BARCODE) %]: barcode not found[% END %]
49
            [% IF ( errorloo.ERR_WTHDRAWN ) %]: item withdrawn[% END %]
91
            [% IF (error.ERR_WTHDRAWN) %]: item withdrawn[% END %]
50
            [% IF ( errorloo.ERR_ONLOAN_RET ) %]: item was on loan. It was returned before marked as seen[% END %]
92
            [% IF (error.ERR_ONLOAN_RET) %]: item was on loan. It was returned before marked as seen[% END %]
51
            [% IF ( errorloo.ERR_ONLOAN_NOT_RET ) %]: item was on loan. couldn't be returned.[% END %]
93
            [% IF (error.ERR_ONLOAN_NOT_RET) %]: item was on loan. couldn't be returned.[% END %]
52
        </div>
94
        </div>
53
    [% END %]
95
    [% END %]
54
	[% UNLESS ( loop ) %]
96
       [% UNLESS op %]
55
	<div class="yui-g">
97
    <div class="yui-g">
56
    <form method="post" action="/cgi-bin/koha/tools/inventory.pl" enctype="multipart/form-data">
98
    <form method="post" action="/cgi-bin/koha/tools/inventory.pl" enctype="multipart/form-data">
57
        <fieldset class="rows">
99
        <fieldset class="rows">
58
            <legend>Use a barcode file</legend>
100
            <legend>Use a barcode file</legend>
59
	 <ol>
101
     <ol>
60
            <li><label for="uploadbarcodes">Barcode file: </label> <input type="file" id="uploadbarcodes" name="uploadbarcodes" /></li>
102
            <li><label for="uploadbarcodes">Barcode file: </label> <input type="file" id="uploadbarcodes" name="uploadbarcodes" /></li>
61
            <li><label for="setdate">Set inventory date to:</label> <input type="text" id="setdate" name="setdate" value="[% today %]" class="datepicker" />
103
            <li><label for="setdate">Set inventory date to:</label> <input type="text" id="setdate" name="setdate" value="[% today %]" class="datepickerfrom" />
62
			<div class="hint">[% INCLUDE 'date-format.inc' %]</div>
63
            </li>
104
            </li>
64
          </ol>
105
          </ol>
65
        </fieldset>
106
        </fieldset>
Lines 81-123 $(document).ready(function(){ Link Here
81
        [% END %]
122
        [% END %]
82
        </select>
123
        </select>
83
        </li>
124
        </li>
84
        [% IF ( authorised_values ) %]
125
        [% IF (authorised_values) %]
85
        <li>
126
        <li>
86
            <label for="locationloop">Shelving location (items.location) is: </label>
127
            <label for="locationloop">Shelving location (items.location) is: </label>
87
        <select id="locationloop" name="location">
128
        <select id="locationloop" name="location">
88
                <option value="">Filter location</option>
129
                <option value="">Filter location</option>
89
        [% FOREACH authorised_value IN authorised_values %]
130
        [% FOREACH value IN authorised_values %]
90
            [% IF ( authorised_value.selected ) %]
131
            [% IF (value.selected) %]
91
                <option value="[% authorised_value.authorised_value %]" selected="selected">[% authorised_value.lib %]</option>
132
                <option value="[% value.authorised_value %]" selected="selected">[% value.lib %]</option>
92
            [% ELSE %]
133
            [% ELSE %]
93
                <option value="[% authorised_value.authorised_value %]">[% authorised_value.lib %]</option>
134
                <option value="[% value.authorised_value %]">[% value.lib %]</option>
94
            [% END %]
135
            [% END %]
95
        [% END %]
136
        [% END %]
96
        </select>        </li>
137
        </select>        </li>
97
        [% END %]
138
        [% END %]
98
        <li>
139
        <li>
99
            <label for="minlocation">Item call number between: </label>
140
            <label for="minlocation">Item callnumber between: </label>
100
                <input type="text" name="minlocation" id="minlocation" value="[% minlocation %]" /> (items.itemcallnumber)  </li>
141
                <input type="text" name="minlocation" id="minlocation" value="[% minlocation %]" /> (items.itemcallnumber)  </li>
101
           <li><label for="maxlocation">...and: </label>
142
           <li><label for="maxlocation">...and: </label>
102
                <input type="text" name="maxlocation" id="maxlocation" value="[% maxlocation %]" />
143
                <input type="text" name="maxlocation" id="maxlocation" value="[% maxlocation %]" />
103
        </li>
144
        </li>
104
        [% IF ( statuses ) %]
145
        [% IF (statuses) %]
105
	</ol>
146
    </ol>
106
	</fieldset>
147
    </fieldset>
107
            <fieldset class="rows">
148
            <fieldset class="rows">
108
            <legend>Item statuses</legend>
149
            <legend>Item statuses</legend>
109
            <div name="statuses" style="display: block;">
150
            <div name="statuses" style="display: block;">
110
                  [% FOREACH statuse IN statuses %]
151
                  [% FOREACH status IN statuses %]
111
                      [% IF ( statuse.values ) %]
152
                      [% IF (status.values) %]
112
                          <fieldset style="float: left; padding: 5px; margin: 5px;text-align:right">
153
                          <fieldset style="float: left; padding: 5px; margin: 5px;text-align:right">
113
                              <legend>[% statuse.fieldname %]</legend>
154
                              <legend>[% status.fieldname %]</legend>
114
                              <ul id="statuses-[% statuse.fieldname %]" style="display: inline;">
155
                              <ul id="statuses-[% fieldname %]" style="display: inline;">
115
                              [% FOREACH value IN statuse.values %]
156
                              [% FOREACH value IN status.values %]
116
                                  [% IF ( value.lib ) %]<li>
157
                                  [% IF (value.lib) %]<li>
117
                                    <label for="[% value.id %]">
158
                                    <label for="[% value.id %]">
118
                                      [% value.lib %]
159
                                      [% value.lib %]
119
                                    </label>
160
                                    </label>
120
                                    <input type="checkbox" name="status-[% value.fieldname %]-[% value.id %]" id="[% value.id %]" />
161
                                    <input type="checkbox" name="status-[% status.fieldname %]-[% value.authorised_value %]" id="[% value.authorised_value %]" />
121
                                  </li>[% END %]
162
                                  </li>[% END %]
122
                              [% END %]
163
                              [% END %]
123
                              </ul>
164
                              </ul>
Lines 126-150 $(document).ready(function(){ Link Here
126
                  [% END %]
167
                  [% END %]
127
                </div>
168
                </div>
128
            </fieldset>
169
            </fieldset>
129
		<fieldset class="rows">
170
        <fieldset class="rows">
130
          <ol>
171
          <ol>
131
        [% END %]
172
        [% END %]
132
173
133
        <li><label for="datelastseen">Inventory date:</label>
174
        <li><label for="datelastseen">Inventory date:</label>
134
            <input type="text" id="datelastseen" name="datelastseen" value="[% datelastseen %]" class="datepicker"/>
175
            <input type="text" id="datelastseen" name="datelastseen" value="[% datelastseen %]" class="datepickerfrom" />
135
			<div class="hint">[% INCLUDE 'date-format.inc' %]</div>
136
        </li>
176
        </li>
137
        <li><label for="ignoreissued">Skip copies on loan: </label>
177
        <li><label for="ignoreissued">Skip copies on loan: </label>
138
            [% IF ( ignoreissued ) %]
178
            [% IF (ignoreissued) %]
139
            <input type="checkbox" id="ignoreissued" name="ignoreissued" checked="checked" /></li>
179
            <input type="checkbox" id="ignoreissued" name="ignoreissued" checked="checked" /></li>
140
            [% ELSE %]
180
            [% ELSE %]
141
            <input type="checkbox" id="ignoreissued" name="ignoreissued" /></li>
181
            <input type="checkbox" id="ignoreissued" name="ignoreissued" /></li>
142
            [% END %]
182
            [% END %]
143
        <li><label for="pagesize">Show: </label>
144
            <input type="text" id="pagesize" name="pagesize" value="[% pagesize %]" maxlength="5" size="5" /> items</li>
145
          <li><label for="offset">Beginning at offset: </label>
146
            <input type="text" id="offset" name="offset" value="[% offset %]" size="5" maxlength="5" />
147
        </li>
148
        <li>
183
        <li>
149
           <label for="CSVexport">Export to CSV file: </label>
184
           <label for="CSVexport">Export to CSV file: </label>
150
           <input type="checkbox" name="CSVexport" id="CSVexport" />
185
           <input type="checkbox" name="CSVexport" id="CSVexport" />
Lines 158-167 $(document).ready(function(){ Link Here
158
            <input type="hidden" name="op" value="do_it" />
193
            <input type="hidden" name="op" value="do_it" />
159
            <fieldset class="action"><input type="submit" value="Submit" class="button" /></fieldset>
194
            <fieldset class="action"><input type="submit" value="Submit" class="button" /></fieldset>
160
    </form>
195
    </form>
161
	</div>
196
    </div>
162
	</div>
197
    </div>
163
	[% END %]
198
    [% END %]
164
    [% IF ( loop ) %]
199
    [% IF (op) %]
165
    <form method="post" action="/cgi-bin/koha/tools/inventory.pl" class="checkboxed">
200
    <form method="post" action="/cgi-bin/koha/tools/inventory.pl" class="checkboxed">
166
    <input type="hidden" name="markseen" value="1" />
201
    <input type="hidden" name="markseen" value="1" />
167
    <input type="hidden" name="minlocation" value="[% minlocation %]" />
202
    <input type="hidden" name="minlocation" value="[% minlocation %]" />
Lines 171-244 $(document).ready(function(){ Link Here
171
    <input type="hidden" name="datelastseen" value="[% datelastseen %]" />
206
    <input type="hidden" name="datelastseen" value="[% datelastseen %]" />
172
    <input type="hidden" name="pagesize" value="[% pagesize %]" />
207
    <input type="hidden" name="pagesize" value="[% pagesize %]" />
173
    <input type="hidden" name="offset" value="[% offset %]" />
208
    <input type="hidden" name="offset" value="[% offset %]" />
174
    <div style="padding : .3em 0"><a href="#" class="checkall">[Select all]</a> <a href="#" class="clearall">[Clear all]</a></div>
209
    <div><a href="#" class="checkall">[Select All]</a> <a href="#" class="clearall">[Clear All]</a></div>
175
    <table>
210
    <table id="inventoryt">
211
    <thead>
176
        <tr>
212
        <tr>
177
            <th>Seen</th>
213
            <th>Seen</th>
178
            <th>Barcode</th>
214
            <th>Barcode</th>
215
            <th>Location</th>
179
            <th>Title</th>
216
            <th>Title</th>
217
            <th>Status</th>
218
            <th>Lost</th>
219
            <th>Damaged</th>
180
            <th>Unseen since</th>
220
            <th>Unseen since</th>
181
            <th>Problems</th>
221
            <th>Problems</th>
182
        </tr>
222
        </tr>
183
    [% FOREACH loo IN loop %]
223
    </thead>
224
    <tbody>
225
    [% FOREACH result IN loop %]
184
        <tr>
226
        <tr>
185
            <td>
227
            <td>
186
                <input type="checkbox" name="SEEN-[% loo.itemnumber %]" value="1" />
228
            <input type="checkbox" name="SEEN-[% result.itemnumber %]" value="1" />
187
            </td>
229
            </td>
188
            <td>
230
            <td>
189
                [% loo.barcode %]
231
            [% result.barcode | html %]
190
            </td>
232
            </td>
191
            <td>
233
            <td>
192
                <p><b>[% loo.itemcallnumber %]</b> - <a href="#" onclick="window.open('/cgi-bin/koha/catalogue/MARCdetail.pl?biblionumber=[% loo.biblionumber %]','marcview','width=800,height=600,toolbar=0,scrollbars=1');">[% loo.title |html %]</a></p>
234
            [% result.homebranch | html %] [% result.location | html %] [[% result.itemcallnumber | html %]]
193
                <p>[% loo.author %]</p>
194
            </td>
235
            </td>
195
            <td>
236
            <td>
196
                <p>[% loo.datelastseen %]</p>
237
            <p><a href="#" onclick="window.open('/cgi-bin/koha/catalogue/MARCdetail.pl?biblionumber=[% result.biblionumber %]','marcview','width=800,height=600,toolbar=0,scrollbars=1');">[% result.title | html %]</a></p><p>[% result.author | html %]</p>
197
            </td>
238
            </td>
198
            <td>
239
            <td>
199
                 [% IF ( loo.notfoundbarcode ) %]
240
            [% result.notforloan | html %]
200
                     <p style="background: red;">Not found among barcodes in barcodes file.</p>
241
            </td>
201
                 [% ELSIF ( loo.notfoundkoha ) %]
242
            <td>
202
                     <p style="background: red;">Not found in Koha.</p>
243
            [% result.itemlost | html %]
203
                 [% ELSE %]
244
            </td>
204
                     <p style="background: green;">None</p>
245
            <td>
205
                 [% END %]
246
            [% result.damaged | html %]
247
            </td>
248
            <td>
249
            [% result.datelastseen | html %]
250
            </td>
251
            <td>
252
            [% IF (result.wrongplace) %]<p>Item should not have been scanned</p>[% ELSIF (result.missingitem) %]<p>Item missing</p>[% ELSIF (result.changestatus) %]<p>Change item status</p>[% END %]
206
            </td>
253
            </td>
207
        </tr>
254
        </tr>
208
    [% END %]
255
    [% END %]
256
    </tbody>
209
    </table>
257
    </table>
210
    <div style="padding : .3em 0"><a href="#" class="checkall">[Select all]</a> <a href="#" class="clearall">[Clear all]</a></div>
258
    <div class="spacer"></div>
211
     <input type="submit" id="markseen" value="Mark seen" />
259
      <p style="display:block;"><span class="exportSelected"></span></p>
212
    </form>
260
    <div style="padding : .3em 0"><a href="#" class="checkall">[Select All]</a> <a href="#" class="clearall">[Clear All]</a></div>
213
    [% IF ( offset ) %]
261
     <input type="submit" id="markseenandquit" value="Mark seen and quit" />
214
    <form method="post" action="/cgi-bin/koha/tools/inventory.pl">
262
     <input type="submit" value="Mark Seen and Continue &gt;&gt;" id="markseenandcontinuebutton" />
215
        <input type="hidden" name="branch" value="[% branch %]" />
263
     <input type="submit" value="Continue without Marking &gt;&gt;" id="continuewithoutmarkingbutton" class="submit" />
216
        <input type="hidden" name="minlocation" value="[% minlocation %]" />
217
        <input type="hidden" name="maxlocation" value="[% maxlocation %]" />
218
        <input type="hidden" name="location" value="[% location %]" />
219
        <input type="hidden" name="branchcode" value="[% branchcode %]" />
220
        <input type="hidden" name="datelastseen" value="[% datelastseen %]" />
221
        <input type="hidden" name="pagesize" value="[% pagesize %]" />
222
        <input type="hidden" name="offset" value="[% prevoffset %]" />
223
        <input type="hidden" name="op" value="do_it" />
224
        <input type="submit" value="&lt;&lt; Continue without marking" class="submit" />
225
    </form>
226
    [% END %]
227
    [% IF ( nextoffset ) %]
228
    <form method="post">
229
        <input type="hidden" name="branch" value="[% branch %]" />
230
        <input type="hidden" name="location" value="[% location %]" />
231
        <input type="hidden" name="branchcode" value="[% branchcode %]" />
232
        <input type="hidden" name="minlocation" value="[% minlocation %]" />
233
        <input type="hidden" name="maxlocation" value="[% maxlocation %]" />
234
        <input type="hidden" name="datelastseen" value="[% datelastseen %]" />
235
        <input type="hidden" name="pagesize" value="[% pagesize %]" />
236
        <input type="hidden" name="offset" value="[% nextoffset %]" />
237
        <input type="hidden" name="op" value="do_it" />
238
        <input type="submit" value="Continue without marking &gt;&gt;" class="submit" />
239
    </form>
264
    </form>
265
240
    </div>
266
    </div>
241
    [% END %]
267
242
    [% END %]
268
    [% END %]
243
</div>
269
</div>
244
<div class="yui-b">
270
<div class="yui-b">
(-)a/tools/ajax-inventory.pl (+43 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
#
3
4
use Modern::Perl;
5
6
use CGI;
7
use JSON;
8
9
use C4::Auth;
10
use C4::Circulation qw/CanBookBeRenewed/;
11
use C4::Context;
12
use C4::Koha qw/getitemtypeimagelocation/;
13
use C4::Reserves qw/CheckReserves/;
14
use C4::Utils::DataTables;
15
use C4::Output;
16
use C4::Biblio;
17
use C4::Items;
18
use C4::Dates qw/format_date format_date_in_iso/;
19
use C4::Koha;
20
use C4::Branch;    # GetBranches
21
use C4::Reports::Guided;    #_get_column_defs
22
use C4::Charset;
23
use List::MoreUtils qw /none/;
24
25
26
my $input = new CGI;
27
28
# Authentication
29
my ($status, $cookie, $sessionId) = C4::Auth::check_api_auth($input, { tools => 'inventory' });
30
exit unless ($status eq "ok");
31
32
33
my $seen = $input->param('seen');
34
my @seent = split(/\|/, $seen);
35
36
# mark seen if applicable (ie: coming form mark seen checkboxes)
37
foreach ( @seent ) {
38
    /SEEN-(.+)/ and &ModDateLastSeen($1);
39
}
40
41
42
print $input->header('application/json');
43
(-)a/tools/inventory.pl (-82 / +198 lines)
Lines 37-42 use C4::Dates qw/format_date format_date_in_iso/; Link Here
37
use C4::Koha;
37
use C4::Koha;
38
use C4::Branch; # GetBranches
38
use C4::Branch; # GetBranches
39
use C4::Circulation;
39
use C4::Circulation;
40
use C4::Reports::Guided;    #_get_column_defs
41
use C4::Charset;
42
use List::MoreUtils qw/none/;
43
40
44
41
my $minlocation=$input->param('minlocation') || '';
45
my $minlocation=$input->param('minlocation') || '';
42
my $maxlocation=$input->param('maxlocation');
46
my $maxlocation=$input->param('maxlocation');
Lines 52-77 my $pagesize = $input->param('pagesize'); Link Here
52
$pagesize=50 unless $pagesize;
56
$pagesize=50 unless $pagesize;
53
my $branchcode = $input->param('branchcode') || '';
57
my $branchcode = $input->param('branchcode') || '';
54
my $branch     = $input->param('branch');
58
my $branch     = $input->param('branch');
55
my $op = $input->param('op');
59
my $op         = $input->param('op');
56
my $res;    #contains the results loop
60
my $compareinv2barcd = $input->param('compareinv2barcd');
57
# warn "uploadbarcodes : ".$uploadbarcodes;
61
my $res;                                            #contains the results loop
58
# use Data::Dumper; warn Dumper($input);
62
59
63
my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
60
my ($template, $borrowernumber, $cookie)
64
    {   template_name   => "tools/inventory.tmpl",
61
    = get_template_and_user({template_name => "tools/inventory.tmpl",
65
        query           => $input,
62
                query => $input,
66
        type            => "intranet",
63
                type => "intranet",
67
        authnotrequired => 0,
64
                authnotrequired => 0,
68
        flagsrequired   => { tools => 'inventory' },
65
                flagsrequired => {tools => 'inventory'},
69
        debug           => 1,
66
                debug => 1,
70
    }
67
                });
71
);
72
68
73
69
my $branches = GetBranches();
74
my $branches = GetBranches();
70
my @branch_loop;
75
my @branch_loop;
71
for my $branch_hash (keys %$branches) {
76
for my $branch_hash (keys %$branches) {
72
	push @branch_loop, {value => "$branch_hash",
77
    push @branch_loop, {value => "$branch_hash",
73
	                   branchname => $branches->{$branch_hash}->{'branchname'}, 
78
                       branchname => $branches->{$branch_hash}->{'branchname'},
74
	                   selected => ($branch_hash eq $branchcode?1:0)};	
79
                       selected => ($branch_hash eq $branchcode?1:0)};
75
}
80
}
76
81
77
@branch_loop = sort {$a->{branchname} cmp $b->{branchname}} @branch_loop;
82
@branch_loop = sort {$a->{branchname} cmp $b->{branchname}} @branch_loop;
Lines 89-95 for my $fwk (keys %$frameworks){ Link Here
89
      my $data=GetAuthorisedValues($authcode);
94
      my $data=GetAuthorisedValues($authcode);
90
      foreach my $value (@$data){
95
      foreach my $value (@$data){
91
        $value->{selected}=1 if ($value->{authorised_value} eq ($location));
96
        $value->{selected}=1 if ($value->{authorised_value} eq ($location));
92
      }      
97
      }
93
      push @authorised_value_list,@$data;
98
      push @authorised_value_list,@$data;
94
    }
99
    }
95
}
100
}
Lines 105-166 for my $statfield (qw/items.notforloan items.itemlost items.wthdrawn items.damag Link Here
105
        push @$statuses, $hash;
110
        push @$statuses, $hash;
106
    }
111
    }
107
}
112
}
113
114
108
$template->param( statuses => $statuses );
115
$template->param( statuses => $statuses );
109
my $staton = {};								#authorized values that are ticked
116
my $staton = {};                                #authorized values that are ticked
110
for my $authvfield (@$statuses) {
117
for my $authvfield (@$statuses) {
111
    $staton->{$authvfield->{fieldname}} = [];
118
    $staton->{$authvfield->{fieldname}} = [];
112
    for my $authval (@{$authvfield->{values}}){
119
    for my $authval (@{$authvfield->{values}}){
113
        if ( defined $input->param('status-' . $authvfield->{fieldname} . '-' . $authval->{id}) && $input->param('status-' . $authvfield->{fieldname} . '-' . $authval->{id}) eq 'on' ){
120
        if ( defined $input->param('status-' . $authvfield->{fieldname} . '-' . $authval->{authorised_value}) && $input->param('status-' . $authvfield->{fieldname} . '-' . $authval->{authorised_value}) eq 'on' ){
114
            push @{$staton->{$authvfield->{fieldname}}}, $authval->{id};
121
            push @{$staton->{$authvfield->{fieldname}}}, $authval->{authorised_value};
115
        }
122
        }
116
    }
123
    }
117
}
124
}
118
125
126
my $notforloanlist;
119
my $statussth = '';
127
my $statussth = '';
120
for my $authvfield (@$statuses) {
128
for my $authvfield (@$statuses) {
121
    if ( scalar @{$staton->{$authvfield->{fieldname}}} > 0 ){
129
    if ( scalar @{$staton->{$authvfield->{fieldname}}} > 0 ){
122
        my $joinedvals = join ',', @{$staton->{$authvfield->{fieldname}}};
130
        my $joinedvals = join ',', @{$staton->{$authvfield->{fieldname}}};
123
        $statussth .= "$authvfield->{fieldname} in ($joinedvals) and ";
131
        $statussth .= "$authvfield->{fieldname} in ($joinedvals) and ";
132
        $notforloanlist = $joinedvals if ($authvfield->{fieldname} eq "items.notforloan");
124
    }
133
    }
125
}
134
}
126
$statussth =~ s, and $,,g;
135
$statussth =~ s, and $,,g;
127
 
136
$template->param(
128
$template->param(branchloop => \@branch_loop,
137
    branchloop               => \@branch_loop,
129
                authorised_values=>\@authorised_value_list,   
138
    authorised_values        => \@authorised_value_list,
130
                today			=>	C4::Dates->today(),
139
    today                    => C4::Dates->today(),
131
                minlocation => $minlocation,
140
    minlocation              => $minlocation,
132
                maxlocation => $maxlocation,
141
    maxlocation              => $maxlocation,
133
                location=>$location,
142
    location                 => $location,
134
                ignoreissued=>$ignoreissued,
143
    ignoreissued             => $ignoreissued,
135
                branchcode=>$branchcode,      
144
    branchcode               => $branchcode,
136
                branch    => $branch,
145
    branch                   => $branch,
137
                offset => $offset,
146
    offset                   => $offset,
138
                pagesize => $pagesize,
147
    pagesize                 => $pagesize,
139
                datelastseen => $datelastseen,
148
    datelastseen             => $datelastseen,
140
                );
149
    compareinv2barcd         => $compareinv2barcd,
150
    notforloanlist           => $notforloanlist
151
);
152
153
my @notforloans;
154
if (defined $notforloanlist) {
155
    @notforloans = split(/,/, $notforloanlist);
156
}
157
158
159
141
my @brcditems;
160
my @brcditems;
142
if ($uploadbarcodes && length($uploadbarcodes)>0){
161
my $barcodelist;
143
    my $dbh=C4::Context->dbh;
162
my @errorloop;
144
    my $date = format_date_in_iso($input->param('setdate')) || C4::Dates->today('iso');
163
if ( $uploadbarcodes && length($uploadbarcodes) > 0 ) {
145
# 	warn "$date";
164
    my $dbh = C4::Context->dbh;
146
    my $strsth="select * from issues, items where items.itemnumber=issues.itemnumber and items.barcode =?";
165
    my $date = format_date_in_iso( $input->param('setdate') ) || C4::Dates->today('iso');
166
167
    my $strsth  = "select * from issues, items where items.itemnumber=issues.itemnumber and items.barcode =?";
147
    my $qonloan = $dbh->prepare($strsth);
168
    my $qonloan = $dbh->prepare($strsth);
148
    $strsth="select * from items where items.barcode =? and items.wthdrawn = 1";
169
    $strsth="select * from items where items.barcode =? and items.wthdrawn = 1";
149
    my $qwthdrawn = $dbh->prepare($strsth);
170
    my $qwthdrawn = $dbh->prepare($strsth);
150
    my @errorloop;
151
    my $count=0;
152
171
172
    my $count = 0;
153
    # This allows us to handle files where lines are delimited by \r, \n, or \r\n.
173
    # This allows us to handle files where lines are delimited by \r, \n, or \r\n.
154
    my $file_contents = read_file( $uploadbarcodes );
174
    my $file_contents = read_file( $uploadbarcodes );
155
    my @barcodes = split( /\r\n|\n|\r/, $file_contents );
175
    my @barcodes = split( /\r\n|\n|\r/, $file_contents );
156
176
157
    for my $barcode ( @barcodes ){
177
    for my $barcode ( @barcodes ){
158
        if ($qwthdrawn->execute($barcode) &&$qwthdrawn->rows){
178
        $barcode =~ s/\r?\n$//;
159
            push @errorloop, {'barcode'=>$barcode,'ERR_WTHDRAWN'=>1};
179
        $barcodelist .= ($barcodelist) ? '|' . $barcode : $barcode;
160
        }else{
180
        if ( $qwthdrawn->execute($barcode) && $qwthdrawn->rows ) {
161
            my $item = GetItem('', $barcode);
181
            push @errorloop, { 'barcode' => $barcode, 'ERR_WTHDRAWN' => 1 };
162
            if (defined $item && $item->{'itemnumber'}){
182
        } else {
163
                ModItem({ datelastseen => $date }, undef, $item->{'itemnumber'});
183
            my $item = GetItem( '', $barcode );
184
            if ( defined $item && $item->{'itemnumber'} ) {
185
                ModItem( { datelastseen => $date }, undef, $item->{'itemnumber'} );
164
                push @brcditems, $item;
186
                push @brcditems, $item;
165
                $count++;
187
                $count++;
166
                $qonloan->execute($barcode);
188
                $qonloan->execute($barcode);
Lines 177-224 if ($uploadbarcodes && length($uploadbarcodes)>0){ Link Here
177
                push @errorloop, {'barcode'=>$barcode,'ERR_BARCODE'=>1};
199
                push @errorloop, {'barcode'=>$barcode,'ERR_BARCODE'=>1};
178
            }
200
            }
179
        }
201
        }
202
180
    }
203
    }
181
    $qonloan->finish;
204
    $qonloan->finish;
182
    $qwthdrawn->finish;
205
    $qwthdrawn->finish;
183
    $template->param(date=>format_date($date),Number=>$count);
206
    $template->param( date => format_date($date), Number => $count );
184
# 	$template->param(errorfile=>$errorfile) if ($errorfile);
207
    $template->param( errorloop => \@errorloop ) if (@errorloop);
185
    $template->param(errorloop=>\@errorloop) if (@errorloop);
208
209
186
}
210
}
187
#if we want to compare the results to a list of barcodes, or we have no barcode file
211
$template->param(barcodelist => $barcodelist);
188
if ( ! ($uploadbarcodes && length($uploadbarcodes)>0 ) || ( $input->param('compareinv2barcd') eq 'on' && length($uploadbarcodes)>0) ) {
212
189
    if ($markseen) {
213
# now build the result list: inventoried items if requested, and mis-placed items -always-
190
        foreach ($input->param) {
214
my $inventorylist;
191
            /SEEN-(.+)/ and &ModDateLastSeen($1);
215
if ( $markseen or $op ) {
192
        }
216
    # retrieve all items in this range.
217
    my $totalrecords;
218
    ($inventorylist, $totalrecords) = GetItemsForInventory($minlocation, $maxlocation, $location, $itemtype, $ignoreissued, '', $branchcode, $branch, 0, undef , $staton);
219
220
    # Real copy
221
    my @res_copy;
222
    foreach (@$inventorylist) {
223
        push @res_copy, $_;
193
    }
224
    }
194
    if ($markseen or $op) {
225
    $res = \@res_copy;
195
        $res = GetItemsForInventory( $minlocation, $maxlocation, $location, $itemtype, $ignoreissued, $datelastseen, $branchcode, $branch, $offset, $pagesize, $staton );
226
}
196
        $template->param(loop =>$res,
227
197
                        nextoffset => ($offset+$pagesize),
228
# set "missing" flags for all items with a datelastseen before the choosen datelastseen
198
                        prevoffset => ($offset?$offset-$pagesize:0),
229
foreach (@$res) { $_->{missingitem}=1 if C4::Dates->new($_->{datelastseen})->output('iso') lt C4::Dates->new($datelastseen)->output('iso'); }
199
                        );
230
200
    }
231
# removing missing items from loop if "Compare barcodes list to results" has not been checked
201
    if ( defined $input->param('compareinv2barcd') && ( ( $input->param('compareinv2barcd') eq 'on' ) && ( scalar @brcditems != scalar @$res ) ) && length($uploadbarcodes) > 0 ){
232
@$res = grep {!$_->{missingitem} == 1 } @$res if (!$input->param('compareinv2barcd'));
202
        if ( scalar @brcditems > scalar @$res ){
233
203
            for my $brcditem (@brcditems) {
234
# insert "wrongplace" to all scanned items that are not supposed to be in this range
204
                if (! grep( $_->{barcode} =~ /$brcditem->{barcode}/ , @$res) ){
235
# note this list is always displayed, whatever the librarian has choosen for comparison
205
                    $brcditem->{notfoundkoha} = 1;
236
foreach my $temp (@brcditems) {
206
                    push @$res, $brcditem;
237
207
                }
238
  # Saving notforloan code before it's replaced by it's authorised value for later comparison
208
            }
239
  $temp->{'notforloancode'} = $temp->{'notforloan'};
209
        } else {
240
210
            my @notfound;
241
  # Populating with authorised values
211
            for my $item (@$res) {
242
  foreach (keys %$temp) {
212
                if ( ! grep( $_->{barcode} =~ /$item->{barcode}/ , @brcditems) ){
243
        # If the koha field is mapped to a marc field
213
                    $item->{notfoundbarcode} = 1;
244
        my $fc = $temp->{'frameworkcode'} || '';
214
                    push @notfound, $item;
245
        my ($f, $sf) = GetMarcFromKohaField("items.$_", $fc);
215
                }
246
        if ($f and $sf) {
247
            # We replace the code with it's description
248
            my $authvals = C4::Koha::GetKohaAuthorisedValuesFromField($f, $sf, $fc);
249
            if ($authvals and defined $temp->{$_} and defined $authvals->{$temp->{$_}}) {
250
              $temp->{$_} = $authvals->{$temp->{$_}};
216
            }
251
            }
217
            $res = [@$res, @notfound];
218
        }
252
        }
219
    }
253
    }
254
255
    next if $temp->{onloan}; # skip checked out items
256
257
    # If we have scanned items with a non-matching notforloan value
258
    if (none { $temp->{'notforloancode'} eq $_ } @notforloans) {
259
        $temp->{'changestatus'} = 1;
260
        my $biblio = C4::Biblio::GetBiblioData($temp->{biblionumber});
261
        $temp->{title} = $biblio->{title};
262
        $temp->{author} = $biblio->{author};
263
        $temp->{datelastseen} = format_date($temp->{datelastseen});
264
        push @$res, $temp;
265
266
    }
267
    if (none { $temp->{barcode} eq $_->{barcode} && !$_->{'onloan'} } @$inventorylist) {
268
        my $temp2 = { %$temp };
269
        $temp2->{wrongplace}=1;
270
        my $biblio = C4::Biblio::GetBiblioData($temp->{biblionumber});
271
        $temp2->{title} = $biblio->{title};
272
        $temp2->{author} = $biblio->{author};
273
        $temp2->{datelastseen} = format_date($temp->{datelastseen});
274
        push @$res, $temp2;
275
    }
276
}
277
278
# Finally, modifying datelastseen for remaining items
279
my $moddatecount = 0;
280
foreach (@$res) {
281
    unless ($_->{'missingitem'}) {
282
        ModDateLastSeen($_->{'itemnumber'});
283
        $moddatecount++;
284
    }
220
}
285
}
221
286
287
# Removing items that don't have any problems from loop
288
@$res = grep { $_->{missingitem} || $_->{wrongplace} || $_->{changestatus} } @$res;
289
290
$template->param(
291
    moddatecount => $moddatecount,
292
    loop       => $res,
293
    nextoffset => ( $offset + $pagesize ),
294
    prevoffset => ( $offset ? $offset - $pagesize : 0 ),
295
    op         => $op
296
);
297
222
if (defined $input->param('CSVexport') && $input->param('CSVexport') eq 'on'){
298
if (defined $input->param('CSVexport') && $input->param('CSVexport') eq 'on'){
223
    eval {use Text::CSV};
299
    eval {use Text::CSV};
224
    my $csv = Text::CSV->new or
300
    my $csv = Text::CSV->new or
Lines 227-240 if (defined $input->param('CSVexport') && $input->param('CSVexport') eq 'on'){ Link Here
227
        -type       => 'text/csv',
303
        -type       => 'text/csv',
228
        -attachment => 'inventory.csv',
304
        -attachment => 'inventory.csv',
229
    );
305
    );
230
    for my $re (@$res){
306
307
    my $columns_def_hashref = C4::Reports::Guided::_get_column_defs();
308
    foreach my $key ( keys %$columns_def_hashref ) {
309
        my $initkey = $key;
310
        $key =~ s/[^\.]*\.//;
311
        $columns_def_hashref->{$initkey}=NormalizeString($columns_def_hashref->{$initkey});
312
        $columns_def_hashref->{$key} = $columns_def_hashref->{$initkey};
313
    }
314
315
    my @translated_keys;
316
    for my $key (qw / biblioitems.title    biblio.author
317
                      items.barcode        items.itemnumber
318
                      items.homebranch     items.location
319
                      items.itemcallnumber items.notforloan
320
                      items.itemlost       items.damaged
321
                      items.stocknumber
322
                      / ) {
323
       push @translated_keys, $columns_def_hashref->{$key};
324
    }
325
326
    $csv->combine(@translated_keys);
327
    print $csv->string, "\n";
328
329
    my @keys = qw / title author barcode itemnumber homebranch location itemcallnumber notforloan lost damaged stocknumber /;
330
    for my $re (@$res) {
231
        my @line;
331
        my @line;
232
        for my $key (keys %$re) {
332
        for my $key (@keys) {
233
            push @line, $re->{$key};
333
            push @line, $re->{$key};
234
        }
334
        }
335
        if ($re->{wrongplace}) {
336
            push @line, "wrong place";
337
        } elsif ($re->{missingitem}) {
338
            push @line, "missing item";
339
        } elsif ($re->{changestatus}) {
340
            push @line, "change item status";
341
        }
342
        $csv->combine(@line);
343
        print $csv->string, "\n";
344
    }
345
    # Adding not found barcodes
346
    foreach my $error (@errorloop) {
347
    my @line;
348
    if ($error->{'ERR_BARCODE'}) {
349
        push @line, map { $_ eq 'barcode' ? $error->{'barcode'} : ''} @keys;
350
        push @line, "barcode not found";
235
        $csv->combine(@line);
351
        $csv->combine(@line);
236
        print $csv->string, "\n";
352
        print $csv->string, "\n";
237
    }
353
    }
354
    }
238
    exit;
355
    exit;
239
}
356
}
240
357
241
- 

Return to bug 7684