adding barcode generator to Koha
[koha.git] / barcodes / barcodesGenerator.pl
1 #!/usr/bin/perl
2
3 # script to generate items barcodes
4 # written 07/04
5 # by Veleda Matias - matias_veleda@hotmail.com - Physics Library UNLP Argentina and
6 #    Castañeda Sebastian - seba3c@yahoo.com.ar - Physics Library UNLP Argentina and
7
8 # This file is part of Koha.
9 #
10 # Koha is free software; you can redistribute it and/or modify it under the
11 # terms of the GNU General Public License as published by the Free Software
12 # Foundation; either version 2 of the License, or (at your option) any later
13 # version.
14 #
15 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
16 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
17 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License along with
20 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
21 # Suite 330, Boston, MA  02111-1307 USA
22
23 require Exporter;
24
25 use strict;
26
27 use CGI;
28 use C4::Context;
29 use C4::Output;
30 use HTML::Template;
31 use PDF::API2;
32 use PDF::API2::Page;
33 use PDF::API2::PDF::Utils;
34 use C4::Barcodes::PrinterConfig;
35 use Time::localtime; 
36
37
38 # This function returns the path to deal with the correct files, considering
39 # templates set and language.
40 sub getPath {
41         my $type = shift @_;
42         my $templatesSet = C4::Context->preference('template');
43         my $lang = C4::Context->preference('opaclanguages');
44         if ($type eq "intranet") {
45                 return "$ENV{'DOCUMENT_ROOT'}/intranet-tmpl/$templatesSet/$lang";
46         } else {
47                 return "$ENV{'DOCUMENT_ROOT'}/opac-tmpl/$templatesSet/$lang";
48         }
49 }
50
51 # Load a configuration file. Before use this function, check if that file exists.
52 sub loadConfFromFile {
53   my $fileName = shift @_;
54         my %keyValues;
55         open FILE, "<$fileName";
56         while (<FILE>) {
57                 chomp;
58                 if (/\s*([\w_]*)\s*=\s*([\[\]\<\>\w_\s:@,\.-]*)\s*/) {
59                         $keyValues{$1} = $2;
60                 }
61         }
62         close FILE;
63         return %keyValues;
64 }
65
66 # Save settings to a configuration file. It delete previous configuration settings.
67 sub saveConfToFile {
68         my $fileName = shift @_;
69         my %keyValues = %{shift @_};
70         my $i;
71         open FILE, ">$fileName";                        
72         my $i;
73         foreach $i (keys(%keyValues)) {
74     print FILE $i." = ".$keyValues{$i}."\n";
75         }
76         close FILE;
77 }
78
79 # Load the config file.
80 my $filenameConf = &getPath("intranet")."/includes/labelConfig/itemsLabelConfig.conf";
81 my %labelConfig = &loadConfFromFile($filenameConf);
82
83 # Creates a CGI object and take its parameters
84 my $cgi = new CGI;
85 my $from = $cgi->param('from');
86 my $to = $cgi->param('to');
87 my $individualCodes = $cgi->param('individualCodes');
88 my $pageType = $cgi->param('pages');
89 my $label = $cgi->param('label');
90 my $numbersystem = $cgi->param('numbersystem');
91
92 # Generate the checksum from an inventary code
93 sub checksum {
94
95   sub calculateDigit {
96     my $code = shift @_;
97     my $sum = 0;
98           my $odd_parity = 1;
99     my $i;
100     for ($i = length($code) - 1; $i >= 0; $i--){
101            if ( $odd_parity ) {
102                   $sum = $sum + ( 3 * substr($code, $i, 1) );
103      } else {
104                         $sum = $sum + substr($code, $i, 1); }
105                   $odd_parity = !$odd_parity;
106            }
107     my $check_digit = 10 - ($sum%10);
108         if ($check_digit==10) {
109                 $check_digit=0;
110         }
111           return $code.$check_digit;
112   }
113
114   my $currentCode = shift @_;
115   $currentCode = &calculateDigit($currentCode);
116   return $currentCode;
117 }
118
119 # Assigns a temporary name to the PDF file
120 sub assingFilename {
121         my ($from, $to) = @_;
122         my $ip = $cgi->remote_addr();
123         my $random = int(rand(1000000));
124     my $timeObj = localtime();
125         my ($day, $month, $year, $hour, $min, $sec) = ($timeObj->mday,
126                                                                                                    $timeObj->mon + 1,
127                                                                                                    $timeObj->year + 1900,
128                                                                                                    $timeObj->hour,
129                                                                                                    $timeObj->min,
130                                                                                                    $timeObj->sec);
131         my $tmpFileName = $random.'-'.$ip.'-(From '.$from.' to '.$to.')-['.$day.'.'.$month.'.'.$year.']-['.$hour.':'.$min.':'.$sec.'].pdf';
132         return $tmpFileName;
133 }
134
135 # Takes inventary codes from database and if they are between
136 # the interval specify by parameters, it generates the correspond barcodes
137 sub barcodesGenerator {
138   my ($from, $to, $individualCodes) = @_;
139   # Returns a database handler
140   my $dbh = C4::Context->dbh;
141   # Create the query to database
142   my $rangeCondition;
143   if ($individualCodes ne "") {
144     $rangeCondition = "AND (I.barcode IN " . $individualCodes . ")";
145   } else {
146     $rangeCondition =  "AND (I.barcode >= " . $from . " AND I.barcode <="  . $to . " )";
147   }
148          
149   my $query = "SELECT CONCAT('$numbersystem',REPEAT('0',((12 - LENGTH('$numbersystem')) - LENGTH(I.barcode))), I.barcode) AS Codigo, B.title, B.author FROM biblio B, items I WHERE (I.biblionumber = B.biblioNumber ) " .$rangeCondition. " AND (I.barcode <> 'FALTA') ORDER BY Codigo";
150   
151   # Prepare the query
152   my $sth = $dbh->prepare($query);
153   # Executes the query
154   $sth->execute;
155   if ($sth->rows) { # There are inventary codes
156         # Set the temp directory for pdf´s files
157         if (!defined($ENV{'TEMP'})) {
158                 $ENV{'TEMP'} = '/tmp/';
159         }       
160         # Assigns a temporary filename for the pdf file
161         my $tmpFileName = &assingFilename($from, $to);
162         $tmpFileName = $ENV{'TEMP'}.$tmpFileName;
163     # Creates a PDF object
164     my $pdf = PDF::API2->new(-file => $tmpFileName);
165     # Set the positions where barcodes are going to be placed
166         C4::Barcodes::PrinterConfig::setPositionsForX($labelConfig{'marginLeft'}, $labelConfig{'labelWidth'}, $labelConfig{'columns'}, $labelConfig{'pageType'});
167         C4::Barcodes::PrinterConfig::setPositionsForY($labelConfig{'marginBottom'}, $labelConfig{'labelHeigth'}, $labelConfig{'rows'}, $labelConfig{'pageType'});
168     # Creates a font object
169     my $tr = $pdf->corefont('Helvetica-Bold');
170     # Barcode position
171         my ($page, $gfx, $text);
172     while (my ($code,$title,$author) = $sth->fetchrow_array) {
173       # Generetase checksum
174       $code = &checksum($code);
175       # Generate the corresponde barcode to $code
176       my $barcode = $pdf->barcode(-font => $tr, # The font object to use
177                                       -type => 'ean13', # Standard of codification
178                                       -code => $code, # Text to codify
179                                       -extn     => '012345',    # Barcode extension (if it is aplicable)
180                                       -umzn => 10,              # Top limit of the finished bar
181                                       -lmzn => 10,              # Bottom limit of the finished bar
182                                       -zone => 15,              # Bars size
183                                           -quzn => 0,           # Space destinated for legend
184                                       -ofwt => 0.01,    # Bars width
185                                           -fnsz => 8,           # Font size
186                                           -text => ''
187                                      );
188         
189           (my $x, my $y, $pdf, $page, $gfx, $text, $tr, $label) = C4::Barcodes::PrinterConfig::getLabelPosition(
190                                                                                                                                                                 $label, 
191                                                                                                                                                 $pdf, 
192                                                                                                                                                                 $page,
193                                                                                                                                                                 $gfx,
194                                                                                                                                                                 $text,
195                                                                                                                                                                 $tr,
196                                                                                                                                                                 $pageType);     
197       # Assigns a barcodes to $gfx
198           $gfx->barcode($barcode, $x, $y , (72/$labelConfig{'systemDpi'}));
199       # Assigns the additional information to the barcode (Legend)
200           $text->translate($x - 48, $y - 22);
201       $text->text(substr $title, 0, 30);
202       $text->translate($x - 48, $y - 29);
203       $text->text(substr $author, 0, 30);
204     }
205     # Writes the objects added in $gfx to $page
206     $pdf->finishobjects($page,$gfx, $text);
207     # Save changes to the PDF
208     $pdf->saveas;
209     # Close the conection with the PDF file
210     $pdf->end;
211     # Show the PDF file
212     print $cgi->redirect("/cgi-bin/koha/barcodes/pdfViewer.pl?tmpFileName=$tmpFileName");
213   } else {
214         # Rollback and shows the error legend
215     print $cgi->redirect("/cgi-bin/koha/barcodes/barcodes.pl?error=1");
216   }
217   $sth->finish;
218 }
219
220 barcodesGenerator($from, $to, $individualCodes);