[Koha-cvs] koha/intranet/modules/C4 AcademicInfo.pm Accoun... [rel_TG]
Tumer Garip
tgarip at neu.edu.tr
Sat Mar 10 02:35:35 CET 2007
CVSROOT: /sources/koha
Module name: koha
Branch: rel_TG
Changes by: Tumer Garip <tgarip1957> 07/03/10 01:35:34
Added files:
intranet/modules/C4: AcademicInfo.pm Accounts2.pm Acquisition.pm
Amazon.pm Auth.pm Auth_with_ldap.pm
AuthoritiesMarc.pm Biblio.pm Biblioadd.pm
BookShelves.pm Bookfund.pm Bookseller.pm
Boolean.pm Breeding.pm Context.pm
Date-new.pm Date.pm Format.pm Input.pm
Koha.pm Labels.pm Letters.pm Log.pm
Members.pm NewsChannels.pm Output.pm
Print.pm Record.pm Reserves2.pm Review.pm
SMS.pm Search.pm Serials-new.pm Serials.pm
Stats.pm Suggestions.pm Z3950.pm
Log message:
fresh files for rel_TG
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/AcademicInfo.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Accounts2.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Acquisition.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Amazon.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Auth.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Auth_with_ldap.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/AuthoritiesMarc.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Biblio.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Biblioadd.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/BookShelves.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Bookfund.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Bookseller.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Boolean.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Breeding.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Context.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Date-new.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Date.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Format.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Input.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Koha.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Labels.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Letters.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Log.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Members.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/NewsChannels.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Output.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Print.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Record.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Reserves2.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Review.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/SMS.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Search.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Serials-new.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Serials.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Stats.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Suggestions.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/koha/intranet/modules/C4/Z3950.pm?cvsroot=koha&only_with_tag=rel_TG&rev=1.1.2.1
Patches:
Index: AcademicInfo.pm
===================================================================
RCS file: AcademicInfo.pm
diff -N AcademicInfo.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ AcademicInfo.pm 10 Mar 2007 01:35:33 -0000 1.1.2.1
@@ -0,0 +1,258 @@
+package C4::AcademicInfo;
+
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+require Exporter;
+use C4::Context;
+
+use vars qw($VERSION @ISA @EXPORT);
+
+# set the version for version checking
+$VERSION = 0.01;
+
+ at ISA = qw(Exporter);
+ at EXPORT = qw(
+ &academic_information
+ &get_careers
+ &get_career
+ &get_academic_info
+ &add_academic_info
+ &update_academic_info
+ &del_academic_info
+ &get_careers_by_institution
+ &get_educational_institution
+ &add_educational_institution
+ &update_educational_institution
+ &add_career
+ &update_career
+ &del_educational_institution
+ &del_career
+ &get_educational_institutions
+);
+
+
+sub academic_information {
+ my ($borrowernumber) = @_;
+ my $dbh = C4::Context->dbh;
+ my @info;
+ my $query = "SELECT *
+ FROM
+ educational_institutions AS I
+ LEFT JOIN careers AS C ON C.id_institution = I.id_institution
+ LEFT JOIN academic_information AS A ON A.id_career = C.id_career
+ WHERE
+ borrowernumber = ?
+ ";
+ my $sth = $dbh->prepare($query);
+ $sth->execute($borrowernumber);
+ while (my $row = $sth->fetchrow_hashref) {
+ push @info, $row;
+ }
+ return (scalar(@info), @info);
+}
+
+sub get_academic_info {
+ my ($id_career, $borrowernumber) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("SELECT * FROM academic_information WHERE id_career = ? AND borrowernumber = ?");
+ $sth->execute($id_career, $borrowernumber);
+ if ($sth->rows) {
+ return ($sth->fetchrow_hashref);
+ } else {
+ return 0;
+ }
+}
+
+sub del_academic_info {
+ my ($id_career, $borrowernumber) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("DELETE FROM academic_information WHERE id_career = ? AND borrowernumber = ? ");
+ $sth->execute($id_career, $borrowernumber);
+ $sth->finish;
+ return 1;
+}
+
+sub add_academic_info {
+ my ($id_career, $borrowernumber, $student_number, $enter_year, $leave_year, $notes) = @_;
+ if (!get_academic_info($id_career, $borrowernumber)) {
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("INSERT INTO academic_information (id_career, borrowernumber, student_number, enter_year, leave_year, notes) VALUES (?,?,?,?,?,?)");
+ $sth->execute($id_career, $borrowernumber, $student_number, $enter_year, $leave_year, $notes);
+ $sth->finish;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+sub update_academic_info {
+ my ($id_career, $borrowernumber, $student_number, $enter_year, $leave_year, $notes) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("UPDATE academic_information SET student_number = ?, enter_year = ?, leave_year = ?, notes = ? WHERE id_career = ? AND borrowernumber = ?");
+ $sth->execute($student_number, $enter_year, $leave_year, $notes, $id_career, $borrowernumber);
+ $sth->finish;
+ return 1;
+}
+
+
+sub get_career {
+ my ($id_career) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("SELECT * FROM educational_institutions LEFT JOIN careers on educational_institutions.id_institution = careers.id_institution where id_career = ?");
+ $sth->execute($id_career);
+ my $info = $sth->fetchrow_hashref;
+ $sth->finish;
+ return $info;
+}
+
+sub get_educational_institution {
+ my ($id_institution) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("SELECT * FROM educational_institutions WHERE id_institution = ? ORDER BY institution_name");
+ $sth->execute($id_institution);
+ my $info = $sth->fetchrow_hashref;
+ $sth->finish;
+ return $info;
+}
+
+sub get_educational_institutions {
+ my $dbh = C4::Context->dbh;
+ my @results;
+ my $sth = $dbh->prepare("SELECT * FROM educational_institutions ORDER BY institution_name");
+ $sth->execute();
+ while (my $info = $sth->fetchrow_hashref) {
+ push @results, $info;
+ }
+ $sth->finish;
+ return @results;
+}
+
+sub get_careers {
+ my $dbh = C4::Context->dbh;
+ my @careers;
+ my $sth = $dbh->prepare("SELECT * FROM educational_institutions LEFT JOIN careers ON educational_institutions.id_institution = careers.id_institution ORDER BY career_name");
+ $sth->execute();
+ while (my $row = $sth->fetchrow_hashref) {
+ $row->{'full_description'} = $row->{'career_name'} . ' - ' . $row->{'institution_name'};
+ push @careers, $row;
+ }
+ return (scalar(@careers), @careers);
+}
+
+sub get_careers_by_institution {
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("SELECT * FROM educational_institutions");
+ $sth->execute;
+
+ my @results;
+ while (my ($id, $name) = $sth->fetchrow) {
+ my %hash;
+ $hash{'id_institution'} = $id;
+ $hash{'institution_name'} = $name;
+ my @careers;
+ my $sth2 = $dbh->prepare("SELECT * FROM careers WHERE id_institution = ?");
+ $sth2->execute($hash{'id_institution'});
+ while (my $ca = $sth2->fetchrow_hashref) {
+ $ca->{'institution_name'} = $name;
+ push @careers, $ca;
+ }
+ $hash{'careers'} = \@careers;
+ push @results, \%hash;
+ }
+
+ return @results;
+}
+
+sub add_educational_institution {
+ my ($institution_name) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("INSERT INTO educational_institutions (institution_name) VALUES (?)");
+ $sth->execute($institution_name);
+ $sth->finish;
+ return 1;
+}
+
+sub update_educational_institution {
+ my ($id_institution, $institution_name) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("UPDATE educational_institutions SET institution_name = ? WHERE id_institution = ?");
+ $sth->execute($institution_name, $id_institution);
+ $sth->finish;
+ return 1;
+}
+
+sub del_educational_institution {
+ my ($id_institution) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("SELECT * FROM careers WHERE id_institution = ?");
+ $sth->execute($id_institution);
+ while (my $row = $sth->fetchrow_hashref) {
+ del_career($row->{'id_career'})
+ }
+ $sth->finish;
+ my $sth = $dbh->prepare("DELETE FROM educational_institutions WHERE id_institution = ?");
+ $sth->execute($id_institution);
+ $sth->finish;
+ return 1;
+}
+
+sub add_career {
+ my ($id_institution, $career_name) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("INSERT INTO careers (id_institution, career_name) VALUES (?,?)");
+ $sth->execute($id_institution, $career_name);
+ $sth->finish;
+ return 1;
+}
+
+sub update_career {
+ my ($id_career, $career_name) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("UPDATE careers SET career_name = ? WHERE id_career = ?");
+ $sth->execute($career_name, $id_career);
+ $sth->finish;
+ return 1;
+}
+
+sub del_career {
+ my ($id_career) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("DELETE FROM academic_information WHERE id_career = ?");
+ $sth->execute($id_career);
+ $sth->finish;
+ my $sth = $dbh->prepare("DELETE FROM careers WHERE id_career = ?");
+ $sth->execute($id_career);
+ $sth->finish;
+ return 1;
+}
+
+
+1;
+__END__
+=back
+
+=head1 AUTHOR
+
+Physics Library UNLP Argentina
+
+Carlos Sebastian Castañeda seba3c at yahoo.com.ar
+
+=cut
+
+
Index: Accounts2.pm
===================================================================
RCS file: Accounts2.pm
diff -N Accounts2.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Accounts2.pm 10 Mar 2007 01:35:33 -0000 1.1.2.1
@@ -0,0 +1,659 @@
+package C4::Accounts2; #assumes C4/Accounts2
+
+
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+require Exporter;
+use C4::Context;
+use C4::Stats;
+
+use vars qw($VERSION @ISA @EXPORT);
+
+# set the version for version checking
+$VERSION = 0.01;
+
+=head1 NAME
+
+C4::Accounts - Functions for dealing with Koha accounts
+
+=head1 SYNOPSIS
+
+ use C4::Accounts2;
+
+=head1 DESCRIPTION
+
+The functions in this module deal with the monetary aspect of Koha,
+including looking up and modifying the amount of money owed by a
+patron.
+
+=head1 FUNCTIONS
+
+=over 2
+
+=cut
+
+ at ISA = qw(Exporter);
+ at EXPORT = qw(&checkaccount &recordpayment &fixaccounts &makepayment &manualinvoice
+ &getnextacctno &manualcredit &calc_charges &createcharge
+
+ &dailyAccountBalance &addDailyAccountOp &getDailyAccountOp);
+
+=item checkaccount
+
+ $owed = &checkaccount($env, $borrowernumber, $dbh, $date);
+
+Looks up the total amount of money owed by a borrower (fines, etc.).
+
+C<$borrowernumber> specifies the borrower to look up.
+
+C<$dbh> is a DBI::db handle for the Koha database.
+
+C<$env> is ignored.
+
+=cut
+#'
+sub checkaccount {
+ #take borrower number
+ #check accounts and list amounts owing
+ my ($env,$bornumber,$dbh,$date)=@_;
+ my $select="SELECT SUM(amountoutstanding) AS total
+ FROM accountlines
+ WHERE borrowernumber = ?
+ AND amountoutstanding<>0";
+ my @bind = ($bornumber);
+ if ($date ne ''){
+ $select.=" AND date < ?";
+ push(@bind,$date);
+ }
+ # print $select;
+ my $sth=$dbh->prepare($select);
+ $sth->execute(@bind);
+ my $data=$sth->fetchrow_hashref;
+ my $total = $data->{'total'};
+ $sth->finish;
+ # output(1,2,"borrower owes $total");
+ #if ($total > 0){
+ # # output(1,2,"borrower owes $total");
+ # if ($total > 5){
+ # reconcileaccount($env,$dbh,$bornumber,$total);
+ # }
+ #}
+ # pause();
+ return($total);
+}
+
+=item recordpayment
+
+ &recordpayment($env, $borrowernumber, $payment);
+
+Record payment by a patron. C<$borrowernumber> is the patron's
+borrower number. C<$payment> is a floating-point number, giving the
+amount that was paid. C<$env> is a reference-to-hash;
+C<$env-E<gt>{branchcode}> is the code of the branch where payment was
+made.
+
+Amounts owed are paid off oldest first. That is, if the patron has a
+$1 fine from Feb. 1, another $1 fine from Mar. 1, and makes a payment
+of $1.50, then the oldest fine will be paid off in full, and $0.50
+will be credited to the next one.
+
+=cut
+#'
+sub recordpayment{
+ #here we update both the accountoffsets and the account lines
+ my ($env,$bornumber,$data)=@_;
+ my $dbh = C4::Context->dbh;
+ my $newamtos = 0;
+ my $accdata = "";
+ my $branch=$env->{'branchcode'};
+ my $amountleft = $data;
+ # begin transaction
+ my $nextaccntno = getnextacctno($env,$bornumber,$dbh);
+ # get lines with outstanding amounts to offset
+ my $sth = $dbh->prepare("select * from accountlines
+ where (borrowernumber = ?) and (amountoutstanding<>0)
+ order by date");
+ $sth->execute($bornumber);
+ # offset transactions
+ while (($accdata=$sth->fetchrow_hashref) and ($amountleft>0)){
+ if ($accdata->{'amountoutstanding'} < $amountleft) {
+ $newamtos = 0;
+ $amountleft -= $accdata->{'amountoutstanding'};
+ } else {
+ $newamtos = $accdata->{'amountoutstanding'} - $amountleft;
+ $amountleft = 0;
+ }
+ my $thisacct = $accdata->{accountid};
+ my $usth = $dbh->prepare("update accountlines set amountoutstanding= ?
+ where accountid=?");
+ $usth->execute($newamtos,$thisacct);
+ $usth->finish;
+ }
+ # create new line
+ my $usth = $dbh->prepare("insert into accountlines
+ (borrowernumber, accountno,date,amount,description,accounttype,amountoutstanding)
+ values (?,?,now(),?,'Payment,thanks','Pay',?)");
+ $usth->execute($bornumber,$nextaccntno,0-$data,0-$amountleft);
+ $usth->finish;
+# UpdateStats($env,$branch,'payment',$data,'','','',$bornumber);
+ $sth->finish;
+}
+
+=item makepayment
+
+ &makepayment($borrowernumber, $acctnumber, $amount, $branchcode);
+
+Records the fact that a patron has paid off the an amount he or
+she owes.
+
+C<$borrowernumber> is the patron's borrower number. C<$acctnumber> is
+the account that was credited. C<$amount> is the amount paid (this is
+only used to record the payment. C<$branchcode> is the code of the branch where payment
+was made.
+
+=cut
+#'
+# FIXME - I'm not at all sure about the above, because I don't
+# understand what the acct* tables in the Koha database are for.
+
+sub makepayment{
+ #here we update the account lines
+ #updated to check, if they are paying off a lost item, we return the item
+ # from their card, and put a note on the item record
+ my ($bornumber,$accountno,$amount,$user,$type)=@_;
+ my $env;
+my $desc;
+my $pay;
+if ($type eq "Pay"){
+ $desc="Payment,received by -". $user;
+ $pay="Pay";
+}else{
+ $desc="Written-off -by". $user;
+ $pay="W";
+}
+ my $dbh = C4::Context->dbh;
+ # begin transaction
+ my $nextaccntno = getnextacctno($env,$bornumber,$dbh);
+ my $newamtos=0;
+ my $sth=$dbh->prepare("Select * from accountlines where borrowernumber=? and accountno=?");
+ $sth->execute($bornumber,$accountno);
+ my $data=$sth->fetchrow_hashref;
+ $sth->finish;
+
+ $dbh->do(<<EOT);
+ UPDATE accountlines
+ SET amountoutstanding = amountoutstanding-$amount
+ WHERE borrowernumber = $bornumber
+ AND accountno = $accountno
+EOT
+
+
+
+ # create new line
+ my $payment=0-$amount;
+if ($data->{'itemnumber'}){
+$desc.=" ".$data->{'itemnumber'};
+
+ $dbh->do(<<EOT);
+ INSERT INTO accountlines
+ (borrowernumber, accountno, itemnumber,date, amount,
+ description, accounttype, amountoutstanding,offset)
+ VALUES ($bornumber, $nextaccntno, $data->{'itemnumber'},now(), $payment,
+ '$desc', '$pay', 0,$accountno)
+EOT
+}else{
+ $dbh->do(<<EOT);
+INSERT INTO accountlines
+ (borrowernumber, accountno, date, amount,
+ description, accounttype, amountoutstanding,offset)
+ VALUES ($bornumber, $nextaccntno, now(), $payment,
+ '$desc', '$pay', 0,$accountno)
+EOT
+}
+
+ # FIXME - The second argument to &UpdateStats is supposed to be the
+ # branch code.
+# UpdateStats($env,'MAIN',$pay,$amount,'','','',$bornumber);
+ $sth->finish;
+ #check to see what accounttype
+ if ($data->{'accounttype'} eq 'Rep' || $data->{'accounttype'} eq 'L'){
+ returnlost($bornumber,$data->{'itemnumber'});
+ }
+}
+
+=item getnextacctno
+
+ $nextacct = &getnextacctno($env, $borrowernumber, $dbh);
+
+Returns the next unused account number for the patron with the given
+borrower number.
+
+C<$dbh> is a DBI::db handle to the Koha database.
+
+C<$env> is ignored.
+
+=cut
+#'
+# FIXME - Okay, so what does the above actually _mean_?
+sub getnextacctno {
+ my ($env,$bornumber,$dbh)=@_;
+ my $nextaccntno = 1;
+ my $sth = $dbh->prepare("select * from accountlines
+ where (borrowernumber = ?)
+ order by accountno desc");
+ $sth->execute($bornumber);
+ if (my $accdata=$sth->fetchrow_hashref){
+ $nextaccntno = $accdata->{'accountno'} + 1;
+ }
+ $sth->finish;
+ return($nextaccntno);
+}
+
+=item fixaccounts
+
+ &fixaccounts($borrowernumber, $accountnumber, $amount);
+
+=cut
+#'
+# FIXME - I don't know whether used
+sub fixaccounts {
+ my ($borrowernumber,$accountno,$amount)=@_;
+ my $dbh = C4::Context->dbh;
+ my $sth=$dbh->prepare("Select * from accountlines where borrowernumber=?
+ and accountno=?");
+ $sth->execute($borrowernumber,$accountno);
+ my $data=$sth->fetchrow_hashref;
+ # FIXME - Error-checking
+ my $diff=$amount-$data->{'amount'};
+ my $outstanding=$data->{'amountoutstanding'}+$diff;
+ $sth->finish;
+
+ $dbh->do(<<EOT);
+ UPDATE accountlines
+ SET amount = '$amount',
+ amountoutstanding = '$outstanding'
+ WHERE borrowernumber = $borrowernumber
+ AND accountno = $accountno
+EOT
+ }
+
+
+sub returnlost{
+ my ($borrnum,$itemnum)=@_;
+ my $dbh = C4::Context->dbh;
+ my $sth=$dbh->prepare("Update issues set returndate=now() where
+ borrowernumber=? and itemnumber=? and returndate is null");
+ $sth->execute($borrnum,$itemnum);
+ $sth->finish;
+}
+
+=item manualinvoice
+
+ &manualinvoice($borrowernumber, $description, $type,
+ $amount, $user);
+
+C<$borrowernumber> is the patron's borrower number.
+C<$description> is a description of the transaction.
+C<$type> may be one of C<CS>, C<CB>, C<CW>, C<CF>, C<CL>, C<N>, C<L>,
+or C<REF>.
+
+
+=cut
+#'
+
+sub manualinvoice{
+ my ($bornum,$desc,$type,$amount,$user)=@_;
+ my $dbh = C4::Context->dbh;
+ my $insert;
+ my %env;
+ my $accountno=getnextacctno('',$bornum,$dbh);
+ my $amountleft=$amount;
+
+
+ if ($type eq 'N'){
+ $desc.="New Card";
+ }
+
+ if ($type eq 'L' && $desc eq ''){
+ $desc="Lost Item";
+ }
+ if ($type eq 'REF'){
+ $desc="Cash refund";
+ }
+ $amountleft=refund('',$bornum,$amount);
+ my $sth=$dbh->prepare("INSERT INTO accountlines
+ (borrowernumber, accountno, date, amount, description, accounttype, amountoutstanding)
+ VALUES (?, ?, now(), ?, ?, ?, ?)");
+ $sth->execute($bornum, $accountno, $amount, $desc, $type, $amountleft);
+
+}
+
+sub manualcredit{
+ my ($bornum,$accountid,$desc,$type,$amount,$user,$oldaccount)=@_;
+ my $dbh = C4::Context->dbh;
+ my $insert;
+ my $accountno=getnextacctno('',$bornum,$dbh);
+# my $amountleft=$amount;
+my $amountleft;
+my $noerror;
+ if ($type eq 'CN' || $type eq 'CA' || $type eq 'CR'
+ || $type eq 'CF' || $type eq 'CL' || $type eq 'CM'){
+ my $amount2=$amount*-1;
+ ( $amountleft, $noerror,$oldaccount)=fixcredit($dbh,$bornum,$amount2,$accountid,$type,$user);
+ }
+ if ($noerror>0){
+
+## find the accountline desc
+my $sth2=$dbh->prepare("select description from accountlines where accountid=?");
+$sth2->execute($accountid);
+my $desc2=$sth2->fetchrow;
+$desc.=" Credited for ".$desc2." by ".$user;
+$sth2->finish;
+
+ my $sth=$dbh->prepare("INSERT INTO accountlines
+ (borrowernumber, accountno, date, amount, description, accounttype, amountoutstanding,offset)
+ VALUES (?, ?, now(), ?, ?, ?, ?,?)");
+ $sth->execute($bornum, $accountno, $amount, $desc, $type, $amountleft,$oldaccount);
+
+return ("0");
+} else {
+ return("1");
+}
+}
+# fixcredit
+sub fixcredit{
+ #here we update both the accountoffsets and the account lines
+ my ($dbh,$bornumber,$data,$accountid,$type,$user)=@_;
+ my $newamtos = 0;
+ my $accdata = "";
+ my $amountleft = $data;
+ my $env;
+ my $query="Select * from accountlines where accountid=? and amountoutstanding > 0";
+ my $sth=$dbh->prepare($query);
+$sth->execute($accountid);
+ $accdata=$sth->fetchrow_hashref;
+ $sth->finish;
+
+if ($accdata){
+ if ($accdata->{'amountoutstanding'} < $amountleft) {
+ $newamtos = 0;
+ $amountleft -= $accdata->{'amountoutstanding'};
+ } else {
+ $newamtos = $accdata->{'amountoutstanding'} - $amountleft;
+ $amountleft = 0;
+ }
+ my $thisacct = $accdata->{accountid};
+ my $usth = $dbh->prepare("update accountlines set amountoutstanding= ?
+ where accountid=?");
+ $usth->execute($newamtos,$thisacct);
+ $usth->finish;
+
+ # begin transaction
+ # get lines with outstanding amounts to offset
+ my $sth = $dbh->prepare("select * from accountlines
+ where (borrowernumber = ?) and (amountoutstanding >0)
+ order by date");
+ $sth->execute($bornumber);
+# print $query;
+ # offset transactions
+ while (($accdata=$sth->fetchrow_hashref) and ($amountleft>0)){
+ if ($accdata->{'amountoutstanding'} < $amountleft) {
+ $newamtos = 0;
+ $amountleft -= $accdata->{'amountoutstanding'};
+ } else {
+ $newamtos = $accdata->{'amountoutstanding'} - $amountleft;
+ $amountleft = 0;
+ }
+ my $thisacct = $accdata->{accountid};
+ my $usth = $dbh->prepare("update accountlines set amountoutstanding= ?
+ where accountid=?");
+ $usth->execute($newamtos,$thisacct);
+ $usth->finish;
+ }## while account
+ $sth->finish;
+
+ $amountleft*=-1;
+ return($amountleft,1,$accdata->{'accountno'});
+}else{
+return("",0);
+}
+}
+
+
+#
+sub refund{
+ #here we update both the accountoffsets and the account lines
+ my ($env,$bornumber,$data)=@_;
+ my $dbh = C4::Context->dbh;
+ my $newamtos = 0;
+ my $accdata = "";
+# my $branch=$env->{'branchcode'};
+ my $amountleft = $data *-1;
+
+ # begin transaction
+ # get lines with outstanding amounts to offset
+ my $sth = $dbh->prepare("select * from accountlines
+ where (borrowernumber = ?) and (amountoutstanding<0)
+ order by date");
+ $sth->execute($bornumber);
+# print $amountleft;
+ # offset transactions
+ while (($accdata=$sth->fetchrow_hashref) and ($amountleft<0)){
+ if ($accdata->{'amountoutstanding'} > $amountleft) {
+ $newamtos = 0;
+ $amountleft -= $accdata->{'amountoutstanding'};
+ } else {
+ $newamtos = $accdata->{'amountoutstanding'} - $amountleft;
+ $amountleft = 0;
+ }
+# print $amountleft;
+ my $thisacct = $accdata->{accountid};
+ my $usth = $dbh->prepare("update accountlines set amountoutstanding= ?
+ where accountid=?");
+ $usth->execute($newamtos,$thisacct);
+ $usth->finish;
+
+ }
+ $sth->finish;
+ return($amountleft*-1);
+}
+
+#Funtion to manage the daily account#
+
+sub dailyAccountBalance {
+ my ($date) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth;
+
+ if ($date) {
+
+ $sth = $dbh->prepare("SELECT * FROM dailyaccountbalance WHERE balanceDate = ?");
+ $sth->execute($date);
+ my $data = $sth->fetchrow_hashref;
+ if (!$data->{'balanceDate'}) {
+ $data->{'noentry'} = 1;
+ }
+ return ($data);
+
+ } else {
+
+ $sth = $dbh->prepare("SELECT * FROM dailyaccountbalance WHERE balanceDate = CURRENT_DATE()");
+ $sth->execute();
+
+ if ($sth->rows) {
+ return ($sth->fetchrow_hashref);
+ } else {
+ my %hash;
+
+ $sth = $dbh->prepare("SELECT currentBalanceInHand FROM dailyaccountbalance ORDER BY balanceDate DESC LIMIT 1");
+ $sth->execute();
+ if ($sth->rows) {
+ ($hash{'initialBalanceInHand'}) = $sth->fetchrow_array;
+ $hash{'currentBalanceInHand'} = $hash{'initialBalanceInHand'};
+ } else {
+ $hash{'initialBalanceInHand'} = 0;
+ $hash{'currentBalanceInHand'} = 0;
+ }
+ #gets the current date.
+ my @nowarr = localtime();
+ my $date = (1900+$nowarr[5])."-".($nowarr[4]+1)."-".$nowarr[3];
+
+ $hash{'balanceDate'} = $date;
+ $hash{'initialBalanceInHand'} = sprintf ("%.2f", $hash{'initialBalanceInHand'});
+ $hash{'currentBalanceInHand'} = sprintf ("%.2f", $hash{'currentBalanceInHand'});
+ return \%hash;
+ }
+
+ }
+}
+
+sub addDailyAccountOp {
+ my ($description, $amount, $type, $invoice) = @_;
+ my $dbh = C4::Context->dbh;
+ unless ($invoice) { $invoice = undef};
+ my $sth = $dbh->prepare("INSERT INTO dailyaccount (date, description, amount, type, invoice) VALUES (CURRENT_DATE(), ?, ?, ?, ?)");
+ $sth->execute($description, $amount, $type, $invoice);
+ my $accountop = $dbh->{'mysql_insertid'};
+ $sth = $dbh->prepare("SELECT * FROM dailyaccountbalance WHERE balanceDate = CURRENT_DATE()");
+ $sth->execute();
+ if (!$sth->rows) {
+ $sth = $dbh->prepare("SELECT currentBalanceInHand FROM dailyaccountbalance ORDER BY balanceDate DESC LIMIT 1");
+ $sth->execute();
+ my ($blc) = $sth->fetchrow_array;
+ unless ($blc) {$blc = 0}
+ $sth = $dbh->prepare("INSERT INTO dailyaccountbalance (balanceDate, initialBalanceInHand, currentBalanceInHand) VALUES (CURRENT_DATE(), ?, ?)");
+ $sth->execute($blc, $blc);
+ }
+ if ($type eq 'D') {
+ $amount = -1 * $amount;
+ }
+ $sth = $dbh->prepare("UPDATE dailyaccountbalance SET currentBalanceInHand = currentBalanceInHand + ? WHERE balanceDate = CURRENT_DATE()");
+ $sth->execute($amount);
+ return $accountop;
+}
+
+sub getDailyAccountOp {
+ my ($date) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth;
+ if ($date) {
+ $sth = $dbh->prepare("SELECT * FROM dailyaccount WHERE date = ?");
+ $sth->execute($date);
+ } else {
+ $sth = $dbh->prepare("SELECT * FROM dailyaccount WHERE date = CURRENT_DATE()");
+ $sth->execute();
+ }
+ my @operations;
+ my $count = 1;
+ while (my $row = $sth->fetchrow_hashref) {
+ $row->{'num'} = $count++;
+ $row->{$row->{'type'}} = 1;
+
+ $row->{'invoice'} =~ /(\w*)\-(\w*)\-(\w*)/;
+ $row->{'invoiceNumber'} = $1;
+ $row->{'invoiceSupplier'} = $2;
+ $row->{'invoiceType'} = $3;
+
+ push @operations, $row;
+ }
+ return (scalar(@operations), \@operations);
+}
+
+=item calc_charges
+
+ ($charge, $item_type) = &calc_charges($env, $itemnumber, $borrowernumber);
+
+Calculate how much it would cost for a given patron to borrow a given
+item, including any applicable discounts.
+
+C<$env> is ignored.
+
+C<$itemnumber> is the item number of item the patron wishes to borrow.
+
+C<$borrowernumber> is the patron's borrower number.
+
+C<&calc_charges> returns two values: C<$charge> is the rental charge,
+and C<$item_type> is the code for the item's item type (e.g., C<VID>
+if it's a video).
+
+=cut
+
+sub calc_charges {
+ # calculate charges due
+ my ($env, $itemnumber, $bornum)=@_;
+ my $charge=0;
+ my $dbh = C4::Context->dbh;
+ my $sth= $dbh->prepare("select ctype from items where itemnumber=?");
+ $sth->execute($itemnumber);
+ my $itemtype=$sth->fetchrow;
+ $sth->finish;
+
+ my $sth1= $dbh->prepare("select rentalcharge from itemtypes where itemtypes.itemtype=?");
+ $sth1->execute($itemtype);
+
+ $charge = $sth1->fetchrow;
+ my $q2 = "select rentaldiscount from issuingrules,borrowers
+ where (borrowers.borrowernumber = ?)
+ and (borrowers.categorycode = issuingrules.categorycode)
+ and (issuingrules.itemtype = ?)";
+ my $sth2=$dbh->prepare($q2);
+ $sth2->execute($bornum,$itemtype);
+ if (my $data2=$sth2->fetchrow_hashref) {
+ my $discount = $data2->{'rentaldiscount'};
+ if ($discount eq 'NULL') {
+ $discount=0;
+ }
+ $charge = ($charge *(100 - $discount)) / 100;
+ # warn "discount is $discount";
+ }
+ $sth2->finish;
+
+ $sth1->finish;
+ return ($charge,$itemtype);
+}
+
+
+
+sub createcharge {
+
+ my ($env,$dbh,$itemnumber,$bornum,$charge) = @_;
+ my $nextaccntno = getnextacctno($env,$bornum,$dbh);
+ my $sth = $dbh->prepare(<<EOT);
+ INSERT INTO accountlines
+ (borrowernumber, itemnumber, accountno,
+ date, amount, description, accounttype,
+ amountoutstanding)
+ VALUES (?, ?, ?,
+ now(), ?, 'Rental', 'Rent',
+ ?)
+EOT
+ $sth->execute($bornum, $itemnumber, $nextaccntno, $charge, $charge);
+ $sth->finish;
+}
+
+1;
+__END__
+
+=back
+
+=head1 SEE ALSO
+
+DBI(3)
+
+=cut
Index: Acquisition.pm
===================================================================
RCS file: Acquisition.pm
diff -N Acquisition.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Acquisition.pm 10 Mar 2007 01:35:33 -0000 1.1.2.1
@@ -0,0 +1,973 @@
+package C4::Acquisition;
+
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+# $Id: Acquisition.pm,v 1.1.2.1 2007/03/10 01:35:33 tgarip1957 Exp $
+
+use strict;
+require Exporter;
+use C4::Context;
+use C4::Date;
+use C4::Suggestions;
+use C4::Biblio;
+use Time::localtime;
+
+use vars qw($VERSION @ISA @EXPORT);
+
+# set the version for version checking
+$VERSION = do { my @v = '$Revision: 1.1.2.1 $' =~ /\d+/g; shift(@v) . "." . join( "_", map { sprintf "%03d", $_ } @v ); };
+
+# used in receiveorder subroutine
+# to provide library specific handling
+my $library_name = C4::Context->preference("LibraryName");
+
+=head1 NAME
+
+C4::Acquisition - Koha functions for dealing with orders and acquisitions
+
+=head1 SYNOPSIS
+
+use C4::Acquisition;
+
+=head1 DESCRIPTION
+
+The functions in this module deal with acquisitions, managing book
+orders, basket and parcels.
+
+=head1 FUNCTIONS
+
+=over 2
+
+=cut
+
+ at ISA = qw(Exporter);
+ at EXPORT = qw(
+ &GetBasket &NewBasket &CloseBasket
+ &GetPendingOrders &GetOrder &GetOrders
+ &GetOrderNumber &GetLateOrders &NewOrder &DelOrder
+ &GetHistory
+ &ModOrder &ModReceiveOrder
+ &GetSingleOrder
+);
+
+
+=head2 FUNCTIONS ABOUT BASKETS
+
+=over 2
+
+=cut
+
+#------------------------------------------------------------#
+
+=head3 GetBasket
+
+=over 4
+
+$aqbasket = &GetBasket($basketnumber);
+
+get all basket informations in aqbasket for a given basket
+
+return :
+informations for a given basket returned as a hashref.
+
+=back
+
+=back
+
+=cut
+
+sub GetBasket {
+ my ($basketno) = shift;
+ my $dbh = C4::Context->dbh;
+ my $query = "
+ SELECT aqbasket.*,
+ concat(borrowers.firstname,' ',borrowers.surname) AS authorisedbyname,
+ borrowers.branchcode AS branch
+ FROM aqbasket
+ LEFT JOIN borrowers ON aqbasket.authorisedby=borrowers.borrowernumber
+ WHERE basketno=?
+ ";
+ my $sth=$dbh->prepare($query);
+ $sth->execute($basketno);
+ return ( $sth->fetchrow_hashref );
+}
+
+#------------------------------------------------------------#
+
+=head3 NewBasket
+
+=over 4
+
+$basket = &NewBasket();
+
+Create a new basket in aqbasket table
+
+=back
+
+=cut
+
+# FIXME : this function seems to be unused.
+
+sub NewBasket {
+ my ( $booksellerid, $authorisedby ) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = "
+ INSERT INTO aqbasket
+ (creationdate,booksellerid,authorisedby)
+ VALUES (now(),'$booksellerid','$authorisedby')
+ ";
+ my $sth =
+ $dbh->do($query);
+
+#find & return basketno MYSQL dependant, but $dbh->last_insert_id always returns null :-(
+ my $basket = $dbh->{'mysql_insertid'};
+ return $basket;
+}
+
+#------------------------------------------------------------#
+
+=head3 CloseBasket
+
+=over 4
+
+&CloseBasket($basketno);
+
+close a basket (becomes unmodifiable,except for recieves)
+
+=back
+
+=cut
+
+sub CloseBasket {
+ my ($basketno) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = "
+ UPDATE aqbasket
+ SET closedate=now()
+ WHERE basketno=?
+ ";
+ my $sth = $dbh->prepare($query);
+ $sth->execute($basketno);
+}
+
+#------------------------------------------------------------#
+
+=back
+
+=head2 FUNCTIONS ABOUT ORDERS
+
+=over 2
+
+=cut
+
+#------------------------------------------------------------#
+
+=head3 GetPendingOrders
+
+=over 4
+
+$orders = &GetPendingOrders($booksellerid);
+
+Finds pending orders from the bookseller with the given ID. Ignores
+completed and cancelled orders.
+
+C<$orders> is a reference-to-array; each element is a
+reference-to-hash with the following fields:
+
+=over 2
+
+=item C<authorizedby>
+
+=item C<entrydate>
+
+=item C<basketno>
+
+These give the value of the corresponding field in the aqorders table
+of the Koha database.
+
+=back
+
+=back
+
+Results are ordered from most to least recent.
+
+=cut
+
+sub GetPendingOrders {
+ my $supplierid = shift;
+ my $dbh = C4::Context->dbh;
+ my $strsth = "SELECT aqorders.*,aqbasket.*,borrowers.firstname,borrowers.surname
+ FROM aqorders
+ LEFT JOIN aqbasket ON aqbasket.basketno=aqorders.basketno
+ LEFT JOIN borrowers ON aqbasket.authorisedby=borrowers.borrowernumber
+ WHERE booksellerid=?
+ AND (quantity > quantityreceived OR quantityreceived is NULL)
+ AND datecancellationprinted IS NULL
+ AND (to_days(now())-to_days(closedate) < 180 OR closedate IS NULL) ";
+
+ if ( C4::Context->preference("IndependantBranches") ) {
+ my $userenv = C4::Context->userenv;
+ if ( ($userenv) && ( $userenv->{flags} != 1 ) ) {
+ $strsth .=
+ " and (borrowers.branchcode = '"
+ . $userenv->{branch}
+ . "' or borrowers.branchcode ='')";
+ }
+ }
+ $strsth .= " group by aqbasket.basketno order by aqbasket.basketno";
+ my $sth = $dbh->prepare($strsth);
+ $sth->execute($supplierid);
+ my @results;
+ while (my $data = $sth->fetchrow_hashref ) {
+ push @results, $data ;
+ }
+ $sth->finish;
+ return \@results;
+}
+
+#------------------------------------------------------------#
+
+=head3 GetOrders
+
+=over 4
+
+ at orders = &GetOrders($basketnumber, $orderby);
+
+Looks up the non-cancelled orders (whether received or not) with the given basket
+number. If C<$booksellerID> is non-empty, only orders from that seller
+are returned.
+
+return :
+C<&basket> returns a two-element array. C<@orders> is an array of
+references-to-hash, whose keys are the fields from the aqorders,
+biblio, and biblioitems tables in the Koha database.
+
+=back
+
+=cut
+
+sub GetOrders {
+ my ( $basketno, $orderby ) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query ="
+ SELECT aqorderbreakdown.*,
+ biblio.*,
+ aqorders.*
+ FROM aqorders,biblio
+ LEFT JOIN aqorderbreakdown ON
+ aqorders.ordernumber=aqorderbreakdown.ordernumber
+ WHERE basketno=?
+ AND biblio.biblionumber=aqorders.biblionumber
+ AND (datecancellationprinted IS NULL OR datecancellationprinted='0000-00-00')
+ ";
+
+ $orderby = "biblio.title" unless $orderby;
+ $query .= " ORDER BY $orderby";
+ my $sth = $dbh->prepare($query);
+ $sth->execute($basketno);
+ my @results;
+
+ # print $query;
+ while ( my $data = $sth->fetchrow_hashref ) {
+ push @results, $data;
+ }
+ $sth->finish;
+ return @results;
+}
+
+sub GetSingleOrder {
+ my ($ordnum)=@_;
+ my $dbh = C4::Context->dbh;
+ my $sth=$dbh->prepare("Select * from biblio,aqorders left join aqorderbreakdown
+ on aqorders.ordernumber=aqorderbreakdown.ordernumber
+ where aqorders.ordernumber=?
+ and biblio.biblionumber=aqorders.biblionumber");
+ $sth->execute($ordnum);
+ my $data=$sth->fetchrow_hashref;
+ $sth->finish;
+ return($data);
+}
+
+#------------------------------------------------------------#
+
+=head3 GetOrderNumber
+
+=over 4
+
+$ordernumber = &GetOrderNumber($biblioitemnumber, $biblionumber);
+
+Looks up the ordernumber with the given biblionumber
+
+Returns the number of this order.
+
+=item C<$ordernumber> is the order number.
+
+=back
+
+=cut
+sub GetOrderNumber {
+ my ( $biblionumber ) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = "
+ SELECT ordernumber
+ FROM aqorders
+ WHERE biblionumber=?
+
+ ";
+ my $sth = $dbh->prepare($query);
+ $sth->execute( $biblionumber );
+
+ return $sth->fetchrow;
+}
+
+#------------------------------------------------------------#
+
+=head3 GetOrder
+
+=over 4
+
+$order = &GetOrder($ordernumber);
+
+Looks up an order by order number.
+
+Returns a reference-to-hash describing the order. The keys of
+C<$order> are fields from the biblio, , aqorders, and
+aqorderbreakdown tables of the Koha database.
+
+=back
+
+=cut
+
+sub GetOrder {
+ my ($ordnum) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = "
+ SELECT *
+ FROM biblio,aqorders
+ LEFT JOIN aqorderbreakdown ON aqorders.ordernumber=aqorderbreakdown.ordernumber
+ WHERE aqorders.ordernumber=?
+ AND biblio.biblionumber=aqorders.biblionumber
+
+ ";
+ my $sth= $dbh->prepare($query);
+ $sth->execute($ordnum);
+ my $data = $sth->fetchrow_hashref;
+ $sth->finish;
+ return $data;
+}
+
+#------------------------------------------------------------#
+
+=head3 NewOrder
+
+=over 4
+
+ &NewOrder($basket, $biblionumber, $title, $quantity, $listprice,
+ $booksellerid, $who, $notes, $bookfund, $biblioitemnumber, $rrp,
+ $ecost, $gst, $budget, $unitprice, $subscription,
+ $booksellerinvoicenumber);
+
+Adds a new order to the database. Any argument that isn't described
+below is the new value of the field with the same name in the aqorders
+table of the Koha database.
+
+C<$ordnum> is a "minimum order number." After adding the new entry to
+the aqorders table, C<&neworder> finds the first entry in aqorders
+with order number greater than or equal to C<$ordnum>, and adds an
+entry to the aqorderbreakdown table, with the order number just found,
+and the book fund ID of the newly-added order.
+
+C<$budget> is effectively ignored.
+
+C<$subscription> may be either "yes", or anything else for "no".
+
+=back
+
+=cut
+
+sub NewOrder {
+ my (
+ $basketno, $biblionumber, $title, $quantity,
+ $listprice, $booksellerid, $authorisedby, $notes,
+ $bookfund, $rrp, $ecost,
+ $gst, $budget, $cost, $sub,
+ $purchaseorderno, $sort1, $sort2,$discount,$branch
+ )
+ = @_;
+
+ my $year = localtime->year() + 1900;
+ my $month = localtime->mon() + 1; # months starts at 0, add 1
+
+ if ( !$budget || $budget eq 'now' ) {
+ $budget = "now()";
+ }
+
+ if ( $sub eq 'yes' ) {
+ $sub = 1;
+ }
+ else {
+ $sub = 0;
+ }
+
+ # if $basket empty, it's also a new basket, create it
+ unless ($basketno) {
+ $basketno = NewBasket( $booksellerid, $authorisedby );
+ }
+
+ my $dbh = C4::Context->dbh;
+ my $query = "
+ INSERT INTO aqorders
+ ( biblionumber,title,basketno,quantity,listprice,notes,
+ rrp,ecost,gst,unitprice,subscription,sort1,sort2,purchaseordernumber,discount,budgetdate,entrydate)
+ VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,$budget,now() )
+ ";
+ my $sth = $dbh->prepare($query);
+
+ $sth->execute(
+ $biblionumber, $title, $basketno, $quantity, $listprice,
+ $notes, $rrp, $ecost, $gst,
+ $cost, $sub, $sort1, $sort2,$purchaseorderno,$discount
+ );
+ $sth->finish;
+
+ #get ordnum MYSQL dependant, but $dbh->last_insert_id returns null
+ my $ordnum = $dbh->{'mysql_insertid'};
+ my $query = "
+ INSERT INTO aqorderbreakdown (ordernumber,bookfundid,branchcode)
+ VALUES (?,?,?)
+ ";
+ $sth = $dbh->prepare($query);
+ $sth->execute( $ordnum, $bookfund,$branch );
+ $sth->finish;
+ return ( $basketno, $ordnum );
+}
+
+#------------------------------------------------------------#
+
+=head3 ModOrder
+
+=over 4
+
+&ModOrder($title, $ordernumber, $quantity, $listprice,
+ $biblionumber, $basketno, $supplier, $who, $notes,
+ $bookfundid, $bibitemnum, $rrp, $ecost, $gst, $budget,
+ $unitprice, $booksellerinvoicenumber);
+
+Modifies an existing order. Updates the order with order number
+C<$ordernumber> and biblionumber C<$biblionumber>. All other arguments
+update the fields with the same name in the aqorders table of the Koha
+database.
+
+Entries with order number C<$ordernumber> in the aqorderbreakdown
+table are also updated to the new book fund ID.
+
+=back
+
+=cut
+
+sub ModOrder {
+ my (
+ $title, $ordnum, $quantity, $listprice, $biblionumber,
+ $basketno, $supplier, $who, $notes, $bookfund,
+ $rrp, $ecost, $gst, $budget,
+ $cost, $invoice, $sort1, $sort2,$discount,$branch
+ )
+ = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = "
+ UPDATE aqorders
+ SET title=?,
+ quantity=?,listprice=?,basketno=?,
+ rrp=?,ecost=?,unitprice=?,purchaseordernumber=?,gst=?,
+ notes=?,sort1=?, sort2=?,discount=?
+ WHERE ordernumber=? AND biblionumber=?
+ ";
+ my $sth = $dbh->prepare($query);
+ $sth->execute(
+ $title, $quantity, $listprice, $basketno, $rrp,
+ $ecost, $cost, $invoice, $gst, $notes, $sort1,
+ $sort2, $discount,$ordnum, $biblionumber
+ );
+ $sth->finish;
+ my $query = "
+ REPLACE aqorderbreakdown
+ SET ordernumber=?, bookfundid=?, branchcode=?
+ ";
+ $sth = $dbh->prepare($query);
+
+ $sth->execute( $ordnum,$bookfund, $branch );
+
+ $sth->finish;
+}
+
+#------------------------------------------------------------#
+
+
+
+
+#------------------------------------------------------------#
+
+=head3 ModReceiveOrder
+
+=over 4
+
+&ModReceiveOrder($biblionumber, $ordernumber, $quantityreceived, $user,
+ $unitprice, $booksellerinvoicenumber, $biblioitemnumber,
+ $freight, $bookfund, $rrp);
+
+Updates an order, to reflect the fact that it was received, at least
+in part. All arguments not mentioned below update the fields with the
+same name in the aqorders table of the Koha database.
+
+Updates the order with bibilionumber C<$biblionumber> and ordernumber
+C<$ordernumber>.
+
+
+=back
+
+=cut
+
+
+sub ModReceiveOrder {
+ my (
+ $biblionumber, $ordnum, $quantrec, $cost,
+ $invoiceno, $freight, $rrp, $listprice,$input
+ )
+ = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = "
+ UPDATE aqorders
+ SET quantityreceived=quantityreceived+?,datereceived=now(),booksellerinvoicenumber=?,
+ unitprice=?,freight=?,rrp=?,listprice=?
+ WHERE biblionumber=? AND ordernumber=?
+ ";
+ my $sth = $dbh->prepare($query);
+ my $suggestionid = GetSuggestionFromBiblionumber( $dbh, $biblionumber );
+ if ($suggestionid) {
+ ModStatus( $suggestionid, 'AVAILABLE', '', $biblionumber,$input );
+ }
+ $sth->execute( $quantrec, $invoiceno, $cost, $freight, $rrp, $listprice, $biblionumber,
+ $ordnum );
+ $sth->finish;
+
+}
+
+
+#------------------------------------------------------------#
+
+=head3 DelOrder
+
+=over 4
+
+&DelOrder($biblionumber, $ordernumber);
+
+Cancel the order with the given order and biblio numbers. It does not
+delete any entries in the aqorders table, it merely marks them as
+cancelled.
+
+=back
+
+=cut
+
+sub DelOrder {
+ my ( $biblionumber, $ordnum,$user ) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = "
+ UPDATE aqorders
+ SET datecancellationprinted=now(), cancelledby=?
+ WHERE biblionumber=? AND ordernumber=?
+ ";
+ my $sth = $dbh->prepare($query);
+ $sth->execute( $user,$biblionumber, $ordnum );
+ $sth->finish;
+}
+
+
+=back
+
+=back
+
+=head2 FUNCTIONS ABOUT PARCELS
+
+=over 2
+
+=cut
+
+#------------------------------------------------------------#
+
+=head3 GetParcel
+
+=over 4
+
+ at results = &GetParcel($booksellerid, $code, $date);
+
+Looks up all of the received items from the supplier with the given
+bookseller ID at the given date, for the given code (bookseller Invoice number). Ignores cancelled and completed orders.
+
+C<@results> is an array of references-to-hash. The keys of each element are fields from
+the aqorders, biblio tables of the Koha database.
+
+C<@results> is sorted alphabetically by book title.
+
+=back
+
+=cut
+## This routine is not used will be cleaned
+sub GetParcel {
+
+ #gets all orders from a certain supplier, orders them alphabetically
+ my ( $supplierid, $invoice, $datereceived ) = @_;
+ my $dbh = C4::Context->dbh;
+ my @results = ();
+ $invoice .= '%' if $invoice; # add % if we search on a given invoice
+ my $strsth ="
+ SELECT authorisedby,
+ creationdate,
+ aqbasket.basketno,
+ closedate,surname,
+ firstname,
+ biblionumber,
+ aqorders.title,
+ aqorders.ordernumber,
+ aqorders.quantity,
+ aqorders.quantityreceived,
+ aqorders.unitprice,
+ aqorders.listprice,
+ aqorders.rrp,
+ aqorders.ecost
+ FROM aqorders,aqbasket
+ LEFT JOIN borrowers ON aqbasket.authorisedby=borrowers.borrowernumber
+ WHERE aqbasket.basketno=aqorders.basketno
+ AND aqbasket.booksellerid=?
+ AND (aqorders.datereceived= \"$datereceived\" OR aqorders.datereceived is NULL)";
+ $strsth.= " AND aqorders.purchaseordernumber LIKE \"$invoice\"" if $invoice ne "%";
+
+ if ( C4::Context->preference("IndependantBranches") ) {
+ my $userenv = C4::Context->userenv;
+ if ( ($userenv) && ( $userenv->{flags} != 1 ) ) {
+ $strsth .=
+ " and (borrowers.branchcode = '"
+ . $userenv->{branch}
+ . "' or borrowers.branchcode ='')";
+ }
+ }
+ $strsth .= " order by aqbasket.basketno";
+ ### parcelinformation : $strsth
+ my $sth = $dbh->prepare($strsth);
+ $sth->execute($supplierid);
+ while ( my $data = $sth->fetchrow_hashref ) {
+ push @results, $data ;
+ }
+ ### countparcelbiblio: $count
+ $sth->finish;
+
+ return @results;
+}
+
+#------------------------------------------------------------#
+
+=head3 GetParcels
+
+=over 4
+
+$results = &GetParcels($bookseller, $order, $code, $datefrom, $dateto);
+get a lists of parcels.
+
+* Input arg :
+
+=item $bookseller
+is the bookseller this function has to get parcels.
+
+=item $order
+To know on what criteria the results list has to be ordered.
+
+=item $code
+is the booksellerinvoicenumber.
+
+=item $datefrom & $dateto
+to know on what date this function has to filter its search.
+
+* return:
+a pointer on a hash list containing parcel informations as such :
+
+=item Creation date
+
+=item Last operation
+
+=item Number of biblio
+
+=item Number of items
+
+=back
+
+=cut
+### This routine is not used will be cleaned
+sub GetParcels {
+ my ($bookseller,$order, $code, $datefrom, $dateto) = @_;
+ my $dbh = C4::Context->dbh;
+ my $strsth ="
+ SELECT aqorders.booksellerinvoicenumber,
+ datereceived,
+ count(DISTINCT biblionumber) AS biblio,
+ sum(quantity) AS itemsexpected,
+ sum(quantityreceived) AS itemsreceived
+ FROM aqorders, aqbasket
+ WHERE aqbasket.basketno = aqorders.basketno
+ AND aqbasket.booksellerid = $bookseller and datereceived IS NOT NULL
+ ";
+
+ $strsth .= "and aqorders.booksellerinvoicenumber like \"$code%\" " if ($code);
+
+ $strsth .= "and datereceived >=" . $dbh->quote($datefrom) . " " if ($datefrom);
+
+ $strsth .= "and datereceived <=" . $dbh->quote($dateto) . " " if ($dateto);
+
+ $strsth .= "group by aqorders.booksellerinvoicenumber,datereceived ";
+ $strsth .= "order by $order " if ($order);
+ my $sth = $dbh->prepare($strsth);
+
+ $sth->execute;
+ my @results;
+
+ while ( my $data2 = $sth->fetchrow_hashref ) {
+ push @results, $data2;
+ }
+
+ $sth->finish;
+ return @results;
+}
+
+#------------------------------------------------------------#
+
+=head3 GetLateOrders
+
+=over 4
+
+ at results = &GetLateOrders;
+
+Searches for bookseller with late orders.
+
+return:
+the table of supplier with late issues. This table is full of hashref.
+
+=back
+
+=cut
+
+sub GetLateOrders {
+## requirse fixing for KOHA 3 API. Currently does not return publisher
+ my $delay = shift;
+ my $supplierid = shift;
+ my $branch = shift;
+
+ my $dbh = C4::Context->dbh;
+
+ #BEWARE, order of parenthesis and LEFT JOIN is important for speed
+ my $strsth;
+ my $dbdriver = C4::Context->config("db_scheme") || "mysql";
+
+ # warn " $dbdriver";
+ if ( $dbdriver eq "mysql" ) {
+ $strsth = "
+ SELECT aqbasket.basketno,
+ DATE(aqbasket.closedate) AS orderdate,
+ aqorders.quantity - IFNULL(aqorders.quantityreceived,0) AS quantity,
+ aqorders.rrp AS unitpricesupplier,
+ aqorders.ecost AS unitpricelib,
+ (aqorders.quantity - IFNULL(aqorders.quantityreceived,0)) * aqorders.rrp AS subtotal,
+ aqbookfund.bookfundname AS budget,
+ borrowers.branchcode AS branch,
+ aqbooksellers.name AS supplier,
+ aqorders.title,
+ biblio.author,
+
+ DATEDIFF(CURDATE( ),closedate) AS latesince
+ FROM ((
+ (aqorders LEFT JOIN biblio ON biblio.biblionumber = aqorders.biblionumber)
+
+ LEFT JOIN aqorderbreakdown ON aqorders.ordernumber = aqorderbreakdown.ordernumber)
+ LEFT JOIN aqbookfund ON aqorderbreakdown.bookfundid = aqbookfund.bookfundid),
+ (aqbasket LEFT JOIN borrowers ON aqbasket.authorisedby = borrowers.borrowernumber)
+ LEFT JOIN aqbooksellers ON aqbasket.booksellerid = aqbooksellers.id
+ WHERE aqorders.basketno = aqbasket.basketno
+ AND (closedate < DATE_SUB(CURDATE( ),INTERVAL $delay DAY))
+ AND ((datereceived = '' OR datereceived is null)
+ OR (aqorders.quantityreceived < aqorders.quantity) )
+ ";
+ $strsth .= " AND aqbasket.booksellerid = $supplierid " if ($supplierid);
+ $strsth .= " AND borrowers.branchcode like \'" . $branch . "\'"
+ if ($branch);
+ $strsth .=
+ " AND borrowers.branchcode like \'"
+ . C4::Context->userenv->{branch} . "\'"
+ if ( C4::Context->preference("IndependantBranches")
+ && C4::Context->userenv
+ && C4::Context->userenv->{flags} != 1 );
+ $strsth .=" HAVING quantity<>0
+ AND unitpricesupplier<>0
+ AND unitpricelib<>0
+ ORDER BY latesince,basketno,borrowers.branchcode, supplier
+ ";
+ }
+ else {
+ $strsth = "
+ SELECT aqbasket.basketno,
+ DATE(aqbasket.closedate) AS orderdate,
+ aqorders.quantity, aqorders.rrp AS unitpricesupplier,
+ aqorders.ecost as unitpricelib,
+ aqorders.quantity * aqorders.rrp AS subtotal
+ aqbookfund.bookfundname AS budget,
+ borrowers.branchcode AS branch,
+ aqbooksellers.name AS supplier,
+ biblio.title,
+ biblio.author,
+
+ (CURDATE - closedate) AS latesince
+ FROM((
+ (aqorders LEFT JOIN biblio on biblio.biblionumber = aqorders.biblionumber)
+
+ LEFT JOIN aqorderbreakdown on aqorders.ordernumber = aqorderbreakdown.ordernumber)
+ LEFT JOIN aqbookfund ON aqorderbreakdown.bookfundid = aqbookfund.bookfundid),
+ (aqbasket LEFT JOIN borrowers on aqbasket.authorisedby = borrowers.borrowernumber) LEFT JOIN aqbooksellers ON aqbasket.booksellerid = aqbooksellers.id
+ WHERE aqorders.basketno = aqbasket.basketno
+ AND (closedate < (CURDATE -(INTERVAL $delay DAY))
+ AND ((datereceived = '' OR datereceived is null)
+ OR (aqorders.quantityreceived < aqorders.quantity) ) ";
+ $strsth .= " AND aqbasket.booksellerid = $supplierid " if ($supplierid);
+
+ $strsth .= " AND borrowers.branchcode like \'" . $branch . "\'" if ($branch);
+ $strsth .=" AND borrowers.branchcode like \'". C4::Context->userenv->{branch} . "\'"
+ if (C4::Context->preference("IndependantBranches") && C4::Context->userenv->{flags} != 1 );
+ $strsth .=" ORDER BY latesince,basketno,borrowers.branchcode, supplier";
+ }
+ my $sth = $dbh->prepare($strsth);
+ $sth->execute;
+ my @results;
+ my $hilighted = 1;
+ while ( my $data = $sth->fetchrow_hashref ) {
+ $data->{hilighted} = $hilighted if ( $hilighted > 0 );
+ $data->{orderdate} = format_date( $data->{orderdate} );
+ push @results, $data;
+ $hilighted = -$hilighted;
+ }
+ $sth->finish;
+ return @results;
+}
+
+#------------------------------------------------------------#
+
+=head3 GetHistory
+
+=over 4
+
+(\@order_loop, $total_qty, $total_price, $total_qtyreceived)=&GetHistory( $title, $author, $name, $from_placed_on, $to_placed_on )
+
+this function get the search history.
+
+=back
+
+=cut
+
+sub GetHistory {
+ my ( $title, $author, $name, $from_placed_on, $to_placed_on ) = @_;
+ my @order_loop;
+ my $total_qty = 0;
+ my $total_qtyreceived = 0;
+ my $total_price = 0;
+
+# don't run the query if there are no parameters (list would be too long for sure !)
+ if ( $title || $author || $name || $from_placed_on || $to_placed_on ) {
+ my $dbh = C4::Context->dbh;
+ my $query ="
+ SELECT
+ biblio.title,
+ biblio.author,
+ aqorders.basketno,
+ name,aqbasket.creationdate,
+ aqorders.datereceived,
+ aqorders.quantity,
+ aqorders.quantityreceived,
+ aqorders.ecost,
+ aqorders.ordernumber
+ FROM aqorders,aqbasket,aqbooksellers,biblio";
+
+ $query .= ",borrowers "
+ if ( C4::Context->preference("IndependantBranches") );
+
+ $query .="
+ WHERE aqorders.basketno=aqbasket.basketno
+ AND aqbasket.booksellerid=aqbooksellers.id
+ AND biblio.biblionumber=aqorders.biblionumber ";
+
+ $query .= " AND aqbasket.authorisedby=borrowers.borrowernumber"
+ if ( C4::Context->preference("IndependantBranches") );
+
+ $query .= " AND biblio.title LIKE " . $dbh->quote( "%" . $title . "%" )
+ if $title;
+
+ $query .=
+ " AND biblio.author LIKE " . $dbh->quote( "%" . $author . "%" )
+ if $author;
+
+ $query .= " AND name LIKE " . $dbh->quote( "%" . $name . "%" ) if $name;
+
+ $query .= " AND creationdate >" . $dbh->quote($from_placed_on)
+ if $from_placed_on;
+
+ $query .= " AND creationdate<" . $dbh->quote($to_placed_on)
+ if $to_placed_on;
+
+ if ( C4::Context->preference("IndependantBranches") ) {
+ my $userenv = C4::Context->userenv;
+ if ( ($userenv) && ( $userenv->{flags} != 1 ) ) {
+ $query .=
+ " AND (borrowers.branchcode = '"
+ . $userenv->{branch}
+ . "' OR borrowers.branchcode ='')";
+ }
+ }
+ $query .= " ORDER BY booksellerid";
+ my $sth = $dbh->prepare($query);
+ $sth->execute;
+ my $cnt = 1;
+ while ( my $line = $sth->fetchrow_hashref ) {
+ $line->{count} = $cnt++;
+ $line->{toggle} = 1 if $cnt % 2;
+ push @order_loop, $line;
+ $line->{creationdate} = format_date( $line->{creationdate} );
+ $line->{datereceived} = format_date( $line->{datereceived} );
+ $total_qty += $line->{'quantity'};
+ $total_qtyreceived += $line->{'quantityreceived'};
+ $total_price += $line->{'quantity'} * $line->{'ecost'};
+ }
+ }
+ return \@order_loop, $total_qty, $total_price, $total_qtyreceived;
+}
+
+
+1;
+
+__END__
+
+=back
+
+=head1 AUTHOR
+
+Koha Developement team <info at koha.org>
+
+=cut
Index: Amazon.pm
===================================================================
RCS file: Amazon.pm
diff -N Amazon.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Amazon.pm 10 Mar 2007 01:35:33 -0000 1.1.2.1
@@ -0,0 +1,91 @@
+
+package C4::Amazon;
+# Copyright 2004-2005 Joshua Ferraro (jmf at kados dot org)
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+#
+# This module dynamically pulls amazon content into Koha. It does not
+# store the data in Koha's database. You'll need to get a developer's key
+# as well as an associate's tag to use it.
+# FIXME: need to write up more docs.
+#
+# To use this module you need to do three things:
+# 1. get a dev key and associate tag from Amazon
+# 2. uncomment the Amazon stuff in opac-detail.pl
+# 3. add the template variables to opac-detail.tmpl
+# here's what's available:
+# ProductDescription
+# ImageUrlMedium
+# ListPrice
+# url
+# loop SimilarProducts (Product)
+# loop Reviews (rating, Summary)
+#
+use strict;
+require Exporter;
+
+use vars qw($VERSION @ISA @EXPORT);
+
+$VERSION = 0.01;
+
+ at ISA = qw(Exporter);
+
+ at EXPORT = qw(
+ &get_amazon_details
+);
+
+sub get_amazon_details {
+
+my ( $isbn ) = @_;
+
+# insert your dev key here
+my $dev_key='neulibrary-20';
+$isbn=substr($isbn,0,9);
+# insert your associates tag here
+my $af_tag='0YGCZ5GV9ZNGGS7THDG2';
+
+my $asin=$isbn;
+
+# old way from command line: shift @ARGV or die "Usage:perl amazon_http.ol <asin>\n";
+
+#my $url = "http://xml.amazon.com/onca/xml3?t=" . $af_tag .
+# "&dev-t=" . $dev_key .
+# "&type=heavy&f=xml&" .
+# "AsinSearch=" . $asin;
+my $url = "http://xml.amazon.com/onca/xml3?t=$dev_key&dev-t=$af_tag&type=heavy&f=xml&AsinSearch=" . $asin;
+
+#Here's an example asin for the book "Cryptonomicon"
+#0596005423";
+
+use XML::Simple;
+use LWP::Simple;
+my $content = get($url);
+if ($content){
+
+my $xmlsimple = XML::Simple->new();
+my $response = $xmlsimple->XMLin($content,
+ forcearray => [ qw(Details Product AvgCustomerRating CustomerReview ) ],
+);
+return $response;
+#foreach my $result (@{$response->{Details}}){
+# my $product_description = $result->{ProductDescription};
+# my $image = $result->{ImageUrlMedium};
+# my $price = $result->{ListPrice};
+# my $reviews = $result->{
+# return $result;
+#}
+}
+}
\ No newline at end of file
Index: Auth.pm
===================================================================
RCS file: Auth.pm
diff -N Auth.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Auth.pm 10 Mar 2007 01:35:33 -0000 1.1.2.1
@@ -0,0 +1,627 @@
+# -*- tab-width: 8 -*-
+# NOTE: This file uses 8-character tabs; do not change the tab size!
+
+package C4::Auth;
+
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+use Digest::MD5 qw(md5_base64);
+require Exporter;
+use C4::Context;
+use C4::Output; # to get the template
+use C4::Interface::CGI::Output;
+use C4::Members; # getpatroninformation
+use C4::Koha;## to get branch
+# use Net::LDAP;
+# use Net::LDAP qw(:all);
+
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
+
+# set the version for version checking
+$VERSION = 0.01;
+ at ISA = qw(Exporter);
+
+ at EXPORT = qw(
+&checkpw
+);
+=head1 NAME
+
+C4::Auth - Authenticates Koha users
+
+=head1 SYNOPSIS
+
+ use CGI;
+ use C4::Auth;
+
+ my $query = new CGI;
+
+ my ($template, $borrowernumber, $cookie)
+ = get_template_and_user({template_name => "opac-main.tmpl",
+ query => $query,
+ type => "opac",
+ authnotrequired => 1,
+ flagsrequired => {borrow => 1},
+ });
+
+ print $query->header(
+ -type => "text/html",
+ -charset=>"utf-8",
+ -cookie => $cookie
+ ), $template->output;
+
+
+=head1 DESCRIPTION
+
+ The main function of this module is to provide
+ authentification. However the get_template_and_user function has
+ been provided so that a users login information is passed along
+ automatically. This gets loaded into the template.
+
+=head1 FUNCTIONS
+
+=over 2
+
+=cut
+
+
+
+ at ISA = qw(Exporter);
+ at EXPORT = qw(
+ &checkauth
+ &get_template_and_user
+);
+
+=item get_template_and_user
+
+ my ($template, $borrowernumber, $cookie)
+ = get_template_and_user({template_name => "opac-main.tmpl",
+ query => $query,
+ type => "opac",
+ authnotrequired => 1,
+ flagsrequired => {borrow => 1},
+ });
+
+ This call passes the C<query>, C<flagsrequired> and C<authnotrequired>
+ to C<&checkauth> (in this module) to perform authentification.
+ See C<&checkauth> for an explanation of these parameters.
+
+ The C<template_name> is then used to find the correct template for
+ the page. The authenticated users details are loaded onto the
+ template in the HTML::Template LOOP variable C<USER_INFO>. Also the
+ C<sessionID> is passed to the template. This can be used in templates
+ if cookies are disabled. It needs to be put as and input to every
+ authenticated page.
+
+ More information on the C<gettemplate> sub can be found in the
+ Output.pm module.
+
+=cut
+
+
+sub get_template_and_user {
+ my $in = shift;
+ my $template = gettemplate($in->{'template_name'}, $in->{'type'},$in->{'query'});
+ my ($user, $cookie, $sessionID, $flags)
+ = checkauth($in->{'query'}, $in->{'authnotrequired'}, $in->{'flagsrequired'}, $in->{'type'});
+
+ my $borrowernumber;
+ if ($user) {
+ $template->param(loggedinusername => $user);
+ $template->param(sessionID => $sessionID);
+
+ $borrowernumber = getborrowernumber($user);
+ my ($borr, $alternativeflags) = getpatroninformation(undef, $borrowernumber);
+ my @bordat;
+ $bordat[0] = $borr;
+ $template->param(USER_INFO => \@bordat,
+ );
+ my $branches=GetBranches();
+ $template->param(branchname=>$branches->{$borr->{branchcode}}->{branchname},);
+
+ # We are going to use the $flags returned by checkauth
+ # to create the template's parameters that will indicate
+ # which menus the user can access.
+ if ($flags && $flags->{superlibrarian} == 1)
+ {
+ $template->param(CAN_user_circulate => 1);
+ $template->param(CAN_user_catalogue => 1);
+ $template->param(CAN_user_parameters => 1);
+ $template->param(CAN_user_borrowers => 1);
+ $template->param(CAN_user_permission => 1);
+ $template->param(CAN_user_reserveforothers => 1);
+ $template->param(CAN_user_borrow => 1);
+ $template->param(CAN_user_reserveforself => 1);
+ $template->param(CAN_user_editcatalogue => 1);
+ $template->param(CAN_user_updatecharge => 1);
+ $template->param(CAN_user_acquisition => 1);
+ $template->param(CAN_user_management => 1);
+ $template->param(CAN_user_tools => 1); }
+
+ if ($flags && $flags->{circulate} == 1) {
+ $template->param(CAN_user_circulate => 1); }
+
+ if ($flags && $flags->{catalogue} == 1) {
+ $template->param(CAN_user_catalogue => 1); }
+
+
+ if ($flags && $flags->{parameters} == 1) {
+ $template->param(CAN_user_parameters => 1);
+ $template->param(CAN_user_management => 1);
+ $template->param(CAN_user_tools => 1); }
+
+
+ if ($flags && $flags->{borrowers} == 1) {
+ $template->param(CAN_user_borrowers => 1); }
+
+
+ if ($flags && $flags->{permissions} == 1) {
+ $template->param(CAN_user_permission => 1); }
+
+ if ($flags && $flags->{reserveforothers} == 1) {
+ $template->param(CAN_user_reserveforothers => 1); }
+
+
+ if ($flags && $flags->{borrow} == 1) {
+ $template->param(CAN_user_borrow => 1); }
+
+
+ if ($flags && $flags->{reserveforself} == 1) {
+ $template->param(CAN_user_reserveforself => 1); }
+
+
+ if ($flags && $flags->{editcatalogue} == 1) {
+ $template->param(CAN_user_editcatalogue => 1); }
+
+
+ if ($flags && $flags->{updatecharges} == 1) {
+ $template->param(CAN_user_updatecharge => 1); }
+
+ if ($flags && $flags->{acquisition} == 1) {
+ $template->param(CAN_user_acquisition => 1); }
+
+ if ($flags && $flags->{management} == 1) {
+ $template->param(CAN_user_management => 1);
+ $template->param(CAN_user_tools => 1); }
+
+ if ($flags && $flags->{tools} == 1) {
+ $template->param(CAN_user_tools => 1); }
+
+ }
+ if ($in->{'type'} eq "intranet") {
+ $template->param(
+ intranetcolorstylesheet => C4::Context->preference("intranetcolorstylesheet"),
+ intranetstylesheet => C4::Context->preference("intranetstylesheet"),
+ IntranetNav => C4::Context->preference("IntranetNav"),
+
+ );
+
+ }
+ else {
+ $template->param(
+ suggestion => C4::Context->preference("suggestion"),
+ virtualshelves => C4::Context->preference("virtualshelves"),
+ OpacNav => C4::Context->preference("OpacNav"),
+ opacheader => C4::Context->preference("opacheader"),
+ opaccredits => C4::Context->preference("opaccredits"),
+ opacsmallimage => C4::Context->preference("opacsmallimage"),
+ opaclayoutstylesheet => C4::Context->preference("opaclayoutstylesheet"),
+ opaccolorstylesheet => C4::Context->preference("opaccolorstylesheet"),
+ opaclanguagesdisplay => C4::Context->preference("opaclanguagesdisplay"),
+ TemplateEncoding => C4::Context->preference("TemplateEncoding"),
+ opacuserlogin => C4::Context->preference("opacuserlogin"),
+ opacbookbag => C4::Context->preference("opacbookbag"),
+ );
+ }
+ $template->param(
+ TemplateEncoding => C4::Context->preference("TemplateEncoding"),
+ AmazonContent => C4::Context->preference("AmazonContent"),
+ LibraryName => C4::Context->preference("LibraryName"),
+ );
+ return ($template, $borrowernumber, $cookie);
+}
+
+
+=item checkauth
+
+ ($userid, $cookie, $sessionID) = &checkauth($query, $noauth, $flagsrequired, $type);
+
+Verifies that the user is authorized to run this script. If
+the user is authorized, a (userid, cookie, session-id, flags)
+quadruple is returned. If the user is not authorized but does
+not have the required privilege (see $flagsrequired below), it
+displays an error page and exits. Otherwise, it displays the
+login page and exits.
+
+Note that C<&checkauth> will return if and only if the user
+is authorized, so it should be called early on, before any
+unfinished operations (e.g., if you've opened a file, then
+C<&checkauth> won't close it for you).
+
+C<$query> is the CGI object for the script calling C<&checkauth>.
+
+The C<$noauth> argument is optional. If it is set, then no
+authorization is required for the script.
+
+C<&checkauth> fetches user and session information from C<$query> and
+ensures that the user is authorized to run scripts that require
+authorization.
+
+The C<$flagsrequired> argument specifies the required privileges
+the user must have if the username and password are correct.
+It should be specified as a reference-to-hash; keys in the hash
+should be the "flags" for the user, as specified in the Members
+intranet module. Any key specified must correspond to a "flag"
+in the userflags table. E.g., { circulate => 1 } would specify
+that the user must have the "circulate" privilege in order to
+proceed. To make sure that access control is correct, the
+C<$flagsrequired> parameter must be specified correctly.
+
+The C<$type> argument specifies whether the template should be
+retrieved from the opac or intranet directory tree. "opac" is
+assumed if it is not specified; however, if C<$type> is specified,
+"intranet" is assumed if it is not "opac".
+
+If C<$query> does not have a valid session ID associated with it
+(i.e., the user has not logged in) or if the session has expired,
+C<&checkauth> presents the user with a login page (from the point of
+view of the original script, C<&checkauth> does not return). Once the
+user has authenticated, C<&checkauth> restarts the original script
+(this time, C<&checkauth> returns).
+
+The login page is provided using a HTML::Template, which is set in the
+systempreferences table or at the top of this file. The variable C<$type>
+selects which template to use, either the opac or the intranet
+authentification template.
+
+C<&checkauth> returns a user ID, a cookie, and a session ID. The
+cookie should be sent back to the browser; it verifies that the user
+has authenticated.
+
+=cut
+
+
+
+sub checkauth {
+ my $query=shift;
+ # $authnotrequired will be set for scripts which will run without authentication
+ my $authnotrequired = shift;
+ my $flagsrequired = shift;
+ my $type = shift;
+ $type = 'opac' unless $type;
+
+ my $dbh = C4::Context->dbh;
+ my $timeout = C4::Context->preference('timeout');
+ $timeout = 600 unless $timeout;
+
+ my $template_name;
+ if ($type eq 'opac') {
+ $template_name = "opac-auth.tmpl";
+ } elsif ($type eq 'wap') {
+ $template_name = "wap-auth.tmpl";
+ }else {
+ $template_name = "auth.tmpl";
+ }
+
+ # state variables
+ my $loggedin = 0;
+ my %info;
+ my ($userid, $cookie, $sessionID, $flags,$envcookie);
+ my $logout = $query->param('logout.x');
+ if ($userid = $ENV{'REMOTE_USER'}) {
+ # Using Basic Authentication, no cookies required
+ $cookie=$query->cookie(-name => 'sessionID',
+ -value => '',
+ -expires => '');
+ $loggedin = 1;
+ } elsif ($sessionID=$query->cookie('sessionID')) {
+ C4::Context->_new_userenv($sessionID);
+ if (my %hash=$query->cookie('userenv')){
+ C4::Context::set_userenv(
+ $hash{number},
+ $hash{id},
+ $hash{cardnumber},
+ $hash{firstname},
+ $hash{surname},
+ $hash{branch},
+ $hash{branchname},
+ $hash{flags},
+ $hash{emailaddress},
+ );
+ }
+ my ($ip , $lasttime);
+
+ ($userid, $ip, $lasttime) = $dbh->selectrow_array(
+ "SELECT userid,ip,lasttime FROM sessions WHERE sessionid=?",
+ undef, $sessionID);
+ if ($logout) {
+ # voluntary logout the user
+ $dbh->do("DELETE FROM sessions WHERE sessionID='$sessionID'");
+ C4::Context->_unset_userenv($sessionID);
+ $sessionID = undef;
+ $userid = undef;
+ open L, ">>/tmp/sessionlog";
+ my $time=localtime(time());
+ printf L "%20s from %16s logged out at %30s (manually).\n", $userid, $ip, $time;
+ close L;
+ }
+ if ($userid) {
+ if ($lasttime<time()-$timeout) {
+ # timed logout
+ $info{'timed_out'} = 1;
+ $dbh->do("DELETE FROM sessions WHERE sessionID=?", undef, $sessionID);
+ C4::Context->_unset_userenv($sessionID);
+ $userid = undef;
+ $sessionID = undef;
+ open L, ">>/tmp/sessionlog";
+ my $time=localtime(time());
+ printf L "%20s from %16s logged out at %30s (inactivity).\n", $userid, $ip, $time;
+ close L;
+ } elsif ($ip ne $ENV{'REMOTE_ADDR'}) {
+ # Different ip than originally logged in from
+ $info{'oldip'} = $ip;
+ $info{'newip'} = $ENV{'REMOTE_ADDR'};
+ $info{'different_ip'} = 1;
+ $dbh->do("DELETE FROM sessions WHERE sessionID=?", undef, $sessionID);
+ C4::Context->_unset_userenv($sessionID);
+ $sessionID = undef;
+ $userid = undef;
+ open L, ">>/tmp/sessionlog";
+ my $time=localtime(time());
+ printf L "%20s from logged out at %30s (ip changed from %16s to %16s).\n", $userid, $time, $ip, $info{'newip'};
+ close L;
+ } else {
+ $cookie=$query->cookie(-name => 'sessionID',
+ -value => $sessionID,
+ -expires => '');
+ $dbh->do("UPDATE sessions SET lasttime=? WHERE sessionID=?",
+ undef, (time(), $sessionID));
+ $flags = haspermission($dbh, $userid, $flagsrequired);
+ if ($flags) {
+ $loggedin = 1;
+ } else {
+ $info{'nopermission'} = 1;
+ }
+ }
+ }
+ }
+ unless ($userid) {
+ $sessionID=int(rand()*100000).'-'.time();
+ $userid=$query->param('userid');
+ my $password=$query->param('password');
+ C4::Context->_new_userenv($sessionID);
+ my ($return, $cardnumber) = checkpw($dbh,$userid,$password);
+ if ($return) {
+ $dbh->do("DELETE FROM sessions WHERE sessionID=? AND userid=?",
+ undef, ($sessionID, $userid));
+ $dbh->do("INSERT INTO sessions (sessionID, userid, ip,lasttime) VALUES (?, ?, ?, ?)",
+ undef, ($sessionID, $userid, $ENV{'REMOTE_ADDR'}, time()));
+ open L, ">>/tmp/sessionlog";
+ my $time=localtime(time());
+ printf L "%20s from %16s logged in at %30s.\n", $userid, $ENV{'REMOTE_ADDR'}, $time;
+ close L;
+ $cookie=$query->cookie(-name => 'sessionID',
+ -value => $sessionID,
+ -expires => '');
+ if ($flags = haspermission($dbh, $userid, $flagsrequired)) {
+ $loggedin = 1;
+ } else {
+ $info{'nopermission'} = 1;
+ C4::Context->_unset_userenv($sessionID);
+ }
+ if ($return == 1){
+ my ($bornum,$firstname,$surname,$userflags,$branchcode,$branchname,$emailaddress);
+ my $sth=$dbh->prepare("select borrowernumber,firstname,surname,flags,borrowers.branchcode,branchname,emailaddress from borrowers left join branches on borrowers.branchcode=branches.branchcode where userid=?");
+ $sth->execute($userid);
+ ($bornum,$firstname,$surname,$userflags,$branchcode,$branchname, $emailaddress) = $sth->fetchrow if ($sth->rows);
+# warn "$cardnumber,$bornum,$userid,$firstname,$surname,$userflags,$branchcode,$emailaddress";
+ unless ($sth->rows){
+ my $sth=$dbh->prepare("select borrowernumber,firstname,surname,flags,borrowers.branchcode,branchname,emailaddress from borrowers left join branches on borrowers.branchcode=branches.branchcode where cardnumber=?");
+ $sth->execute($cardnumber);
+ ($bornum,$firstname,$surname,$userflags,$branchcode, $branchname,$emailaddress) = $sth->fetchrow if ($sth->rows);
+# warn "$cardnumber,$bornum,$userid,$firstname,$surname,$userflags,$branchcode,$emailaddress";
+ unless ($sth->rows){
+ $sth->execute($userid);
+ ($bornum,$firstname,$surname,$userflags,$branchcode, $branchname, $emailaddress) = $sth->fetchrow if ($sth->rows);
+ }
+# warn "$cardnumber,$bornum,$userid,$firstname,$surname,$userflags,$branchcode,$emailaddress";
+ }
+ my $hash = C4::Context::set_userenv(
+ $bornum,
+ $userid,
+ $cardnumber,
+ $firstname,
+ $surname,
+ $branchcode,
+ $branchname,
+ $userflags,
+ $emailaddress,
+ );
+# warn "$cardnumber,$bornum,$userid,$firstname,$surname,$userflags,$branchcode,$emailaddress";
+ $envcookie=$query->cookie(-name => 'userenv',
+ -value => $hash,
+ -expires => '');
+ } elsif ($return == 2) {
+ #We suppose the user is the superlibrarian
+ my $hash = C4::Context::set_userenv(
+ 0,0,
+ C4::Context->config('user'),
+ C4::Context->config('user'),
+ C4::Context->config('user'),
+ "","",1,C4::Context->preference('KohaAdminEmailAddress')
+ );
+ $envcookie=$query->cookie(-name => 'userenv',
+ -value => $hash,
+ -expires => '');
+ }
+ } else {
+ if ($userid) {
+ $info{'invalid_username_or_password'} = 1;
+ C4::Context->_unset_userenv($sessionID);
+ }
+ }
+ }
+ my $insecure = C4::Context->boolean_preference('insecure');
+ # finished authentification, now respond
+ if ($loggedin || $authnotrequired || (defined($insecure) && $insecure)) {
+ # successful login
+ unless ($cookie) {
+ $cookie=$query->cookie(-name => 'sessionID',
+ -value => '',
+ -expires => '');
+ }
+ if ($envcookie){
+ return ($userid, [$cookie,$envcookie], $sessionID, $flags)
+ } else {
+ return ($userid, $cookie, $sessionID, $flags);
+ }
+ }
+ # else we have a problem...
+ # get the inputs from the incoming query
+ my @inputs =();
+ foreach my $name (param $query) {
+ (next) if ($name eq 'userid' || $name eq 'password');
+ my $value = $query->param($name);
+ push @inputs, {name => $name , value => $value};
+ }
+
+ my $template = gettemplate($template_name, $type,$query);
+ $template->param(INPUTS => \@inputs,
+ intranetcolorstylesheet => C4::Context->preference("intranetcolorstylesheet"),
+ intranetstylesheet => C4::Context->preference("intranetstylesheet"),
+ IntranetNav => C4::Context->preference("IntranetNav"),
+ opacnav => C4::Context->preference("OpacNav"),
+ TemplateEncoding => C4::Context->preference("TemplateEncoding"),
+
+ );
+ $template->param(loginprompt => 1) unless $info{'nopermission'};
+
+ my $self_url = $query->url(-absolute => 1);
+ $template->param(url => $self_url, LibraryName=> => C4::Context->preference("LibraryName"),);
+ $template->param(\%info);
+ $cookie=$query->cookie(-name => 'sessionID',
+ -value => $sessionID,
+ -expires => '');
+
+output_html_with_http_headers($query, $cookie, $template->output());
+ exit;
+}
+
+
+
+
+sub checkpw {
+
+ my ($dbh, $userid, $password) = @_;
+# INTERNAL AUTH
+ my $sth=$dbh->prepare("select password,cardnumber from borrowers where userid=?");
+ $sth->execute($userid);
+ if ($sth->rows) {
+ my ($md5password,$cardnumber) = $sth->fetchrow;
+ if (md5_base64($password) eq $md5password) {
+ return 1,$cardnumber;
+ }
+ }
+ $sth=$dbh->prepare("select password from borrowers where cardnumber=?");
+ $sth->execute($userid);
+ if ($sth->rows) {
+ my ($md5password) = $sth->fetchrow;
+ if (md5_base64($password) eq $md5password) {
+ return 1,$userid;
+ }
+ }
+ if ($userid eq C4::Context->config('user') && $password eq C4::Context->config('pass')) {
+ # Koha superuser account
+ return 2;
+ }
+ if ($userid eq 'demo' && $password eq 'demo' && C4::Context->config('demo')) {
+ # DEMO => the demo user is allowed to do everything (if demo set to 1 in koha.conf
+ # some features won't be effective : modify systempref, modify MARC structure,
+ return 2;
+ }
+ return 0;
+}
+
+sub getuserflags {
+ my $cardnumber=shift;
+ my $dbh=shift;
+ my $userflags;
+ my $sth=$dbh->prepare("SELECT flags FROM borrowers WHERE cardnumber=?");
+ $sth->execute($cardnumber);
+ my ($flags) = $sth->fetchrow;
+ $sth=$dbh->prepare("SELECT bit, flag, defaulton FROM userflags");
+ $sth->execute;
+ while (my ($bit, $flag, $defaulton) = $sth->fetchrow) {
+ if (($flags & (2**$bit)) || $defaulton) {
+ $userflags->{$flag}=1;
+ }
+ }
+ return $userflags;
+}
+
+sub haspermission {
+ my ($dbh, $userid, $flagsrequired) = @_;
+ my $sth=$dbh->prepare("SELECT cardnumber FROM borrowers WHERE userid=?");
+ $sth->execute($userid);
+ my ($cardnumber) = $sth->fetchrow;
+ ($cardnumber) || ($cardnumber=$userid);
+ my $flags=getuserflags($cardnumber,$dbh);
+ my $configfile;
+ if ($userid eq C4::Context->config('user')) {
+ # Super User Account from /etc/koha.conf
+ $flags->{'superlibrarian'}=1;
+ }
+ if ($userid eq 'demo' && C4::Context->config('demo')) {
+ # Demo user that can do "anything" (demo=1 in /etc/koha.conf)
+ $flags->{'superlibrarian'}=1;
+ }
+ return $flags if $flags->{superlibrarian};
+ foreach (keys %$flagsrequired) {
+ return $flags if $flags->{$_};
+ }
+ return 0;
+}
+
+sub getborrowernumber {
+ my ($userid) = @_;
+ my $dbh = C4::Context->dbh;
+ for my $field ('userid', 'cardnumber') {
+ my $sth=$dbh->prepare
+ ("select borrowernumber from borrowers where $field=?");
+ $sth->execute($userid);
+ if ($sth->rows) {
+ my ($bnumber) = $sth->fetchrow;
+ return $bnumber;
+ }
+ }
+ return 0;
+}
+1;
+__END__
+
+=back
+
+=head1 SEE ALSO
+
+CGI(3)
+
+C4::Output(3)
+
+Digest::MD5(3)
+
+=cut
Index: Auth_with_ldap.pm
===================================================================
RCS file: Auth_with_ldap.pm
diff -N Auth_with_ldap.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Auth_with_ldap.pm 10 Mar 2007 01:35:33 -0000 1.1.2.1
@@ -0,0 +1,688 @@
+# -*- tab-width: 8 -*-
+# NOTE: This file uses 8-character tabs; do not change the tab size!
+
+package C4::Auth;
+
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+use Digest::MD5 qw(md5_base64);
+
+require Exporter;
+use C4::Context;
+use C4::Output; # to get the template
+use C4::Interface::CGI::Output;
+use C4::Circulation::Circ2; # getpatroninformation
+use C4::Members;
+# use Net::LDAP;
+# use Net::LDAP qw(:all);
+
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
+
+# set the version for version checking
+$VERSION = 0.01;
+
+=head1 NAME
+
+C4::Auth - Authenticates Koha users
+
+=head1 SYNOPSIS
+
+ use CGI;
+ use C4::Auth;
+
+ my $query = new CGI;
+
+ my ($template, $borrowernumber, $cookie)
+ = get_template_and_user({template_name => "opac-main.tmpl",
+ query => $query,
+ type => "opac",
+ authnotrequired => 1,
+ flagsrequired => {borrow => 1},
+ });
+
+ print $query->header(
+ -type => guesstype($template->output),
+ -cookie => $cookie
+ ), $template->output;
+
+
+=head1 DESCRIPTION
+
+ The main function of this module is to provide
+ authentification. However the get_template_and_user function has
+ been provided so that a users login information is passed along
+ automatically. This gets loaded into the template.
+
+=head1 LDAP specific
+
+ This module is specific to LDAP authentification. It requires Net::LDAP package and a working LDAP server.
+ To use it :
+ * move initial Auth.pm elsewhere
+ * Search the string LOCAL
+ * modify the code between LOCAL and /LOCAL to fit your LDAP server parameters & fields
+ * rename this module to Auth.pm
+ That should be enough.
+
+=head1 FUNCTIONS
+
+=over 2
+
+=cut
+
+
+
+ at ISA = qw(Exporter);
+ at EXPORT = qw(
+ &checkauth
+ &get_template_and_user
+);
+
+=item get_template_and_user
+
+ my ($template, $borrowernumber, $cookie)
+ = get_template_and_user({template_name => "opac-main.tmpl",
+ query => $query,
+ type => "opac",
+ authnotrequired => 1,
+ flagsrequired => {borrow => 1},
+ });
+
+ This call passes the C<query>, C<flagsrequired> and C<authnotrequired>
+ to C<&checkauth> (in this module) to perform authentification.
+ See C<&checkauth> for an explanation of these parameters.
+
+ The C<template_name> is then used to find the correct template for
+ the page. The authenticated users details are loaded onto the
+ template in the HTML::Template LOOP variable C<USER_INFO>. Also the
+ C<sessionID> is passed to the template. This can be used in templates
+ if cookies are disabled. It needs to be put as and input to every
+ authenticated page.
+
+ More information on the C<gettemplate> sub can be found in the
+ Output.pm module.
+
+=cut
+
+
+sub get_template_and_user {
+ my $in = shift;
+ my $template = gettemplate($in->{'template_name'}, $in->{'type'},$in->{'query'});
+ my ($user, $cookie, $sessionID, $flags)
+ = checkauth($in->{'query'}, $in->{'authnotrequired'}, $in->{'flagsrequired'}, $in->{'type'});
+
+ my $borrowernumber;
+ if ($user) {
+ $template->param(loggedinusername => $user);
+ $template->param(sessionID => $sessionID);
+
+ $borrowernumber = getborrowernumber($user);
+ my ($borr, $alternativeflags) = getpatroninformation(undef, $borrowernumber);
+ my @bordat;
+ $bordat[0] = $borr;
+ $template->param(USER_INFO => \@bordat,
+ );
+ # We are going to use the $flags returned by checkauth
+ # to create the template's parameters that will indicate
+ # which menus the user can access.
+ if ($flags && $flags->{superlibrarian} == 1)
+ {
+ $template->param(CAN_user_circulate => 1);
+ $template->param(CAN_user_catalogue => 1);
+ $template->param(CAN_user_parameters => 1);
+ $template->param(CAN_user_borrowers => 1);
+ $template->param(CAN_user_permission => 1);
+ $template->param(CAN_user_reserveforothers => 1);
+ $template->param(CAN_user_borrow => 1);
+ $template->param(CAN_user_reserveforself => 1);
+ $template->param(CAN_user_editcatalogue => 1);
+ $template->param(CAN_user_updatecharge => 1);
+ $template->param(CAN_user_acquisition => 1);
+ $template->param(CAN_user_management => 1);
+ $template->param(CAN_user_tools => 1); }
+
+ if ($flags && $flags->{circulate} == 1) {
+ $template->param(CAN_user_circulate => 1); }
+
+ if ($flags && $flags->{catalogue} == 1) {
+ $template->param(CAN_user_catalogue => 1); }
+
+
+ if ($flags && $flags->{parameters} == 1) {
+ $template->param(CAN_user_parameters => 1);
+ $template->param(CAN_user_management => 1);
+ $template->param(CAN_user_tools => 1); }
+
+
+ if ($flags && $flags->{borrowers} == 1) {
+ $template->param(CAN_user_borrowers => 1); }
+
+
+ if ($flags && $flags->{permissions} == 1) {
+ $template->param(CAN_user_permission => 1); }
+
+ if ($flags && $flags->{reserveforothers} == 1) {
+ $template->param(CAN_user_reserveforothers => 1); }
+
+
+ if ($flags && $flags->{borrow} == 1) {
+ $template->param(CAN_user_borrow => 1); }
+
+
+ if ($flags && $flags->{reserveforself} == 1) {
+ $template->param(CAN_user_reserveforself => 1); }
+
+
+ if ($flags && $flags->{editcatalogue} == 1) {
+ $template->param(CAN_user_editcatalogue => 1); }
+
+
+ if ($flags && $flags->{updatecharges} == 1) {
+ $template->param(CAN_user_updatecharge => 1); }
+
+ if ($flags && $flags->{acquisition} == 1) {
+ $template->param(CAN_user_acquisition => 1); }
+
+ if ($flags && $flags->{management} == 1) {
+ $template->param(CAN_user_management => 1);
+ $template->param(CAN_user_tools => 1); }
+
+ if ($flags && $flags->{tools} == 1) {
+ $template->param(CAN_user_tools => 1); }
+ }
+ $template->param(
+ LibraryName => C4::Context->preference("LibraryName"),
+ );
+ return ($template, $borrowernumber, $cookie);
+}
+
+
+=item checkauth
+
+ ($userid, $cookie, $sessionID) = &checkauth($query, $noauth, $flagsrequired, $type);
+
+Verifies that the user is authorized to run this script. If
+the user is authorized, a (userid, cookie, session-id, flags)
+quadruple is returned. If the user is not authorized but does
+not have the required privilege (see $flagsrequired below), it
+displays an error page and exits. Otherwise, it displays the
+login page and exits.
+
+Note that C<&checkauth> will return if and only if the user
+is authorized, so it should be called early on, before any
+unfinished operations (e.g., if you've opened a file, then
+C<&checkauth> won't close it for you).
+
+C<$query> is the CGI object for the script calling C<&checkauth>.
+
+The C<$noauth> argument is optional. If it is set, then no
+authorization is required for the script.
+
+C<&checkauth> fetches user and session information from C<$query> and
+ensures that the user is authorized to run scripts that require
+authorization.
+
+The C<$flagsrequired> argument specifies the required privileges
+the user must have if the username and password are correct.
+It should be specified as a reference-to-hash; keys in the hash
+should be the "flags" for the user, as specified in the Members
+intranet module. Any key specified must correspond to a "flag"
+in the userflags table. E.g., { circulate => 1 } would specify
+that the user must have the "circulate" privilege in order to
+proceed. To make sure that access control is correct, the
+C<$flagsrequired> parameter must be specified correctly.
+
+The C<$type> argument specifies whether the template should be
+retrieved from the opac or intranet directory tree. "opac" is
+assumed if it is not specified; however, if C<$type> is specified,
+"intranet" is assumed if it is not "opac".
+
+If C<$query> does not have a valid session ID associated with it
+(i.e., the user has not logged in) or if the session has expired,
+C<&checkauth> presents the user with a login page (from the point of
+view of the original script, C<&checkauth> does not return). Once the
+user has authenticated, C<&checkauth> restarts the original script
+(this time, C<&checkauth> returns).
+
+The login page is provided using a HTML::Template, which is set in the
+systempreferences table or at the top of this file. The variable C<$type>
+selects which template to use, either the opac or the intranet
+authentification template.
+
+C<&checkauth> returns a user ID, a cookie, and a session ID. The
+cookie should be sent back to the browser; it verifies that the user
+has authenticated.
+
+=cut
+
+
+
+sub checkauth {
+ my $query=shift;
+ # $authnotrequired will be set for scripts which will run without authentication
+ my $authnotrequired = shift;
+ my $flagsrequired = shift;
+ my $type = shift;
+ $type = 'opac' unless $type;
+
+ my $dbh = C4::Context->dbh;
+ my $timeout = C4::Context->preference('timeout');
+ $timeout = 600 unless $timeout;
+
+ my $template_name;
+ if ($type eq 'opac') {
+ $template_name = "opac-auth.tmpl";
+ } else {
+ $template_name = "auth.tmpl";
+ }
+
+ # state variables
+ my $loggedin = 0;
+ my %info;
+ my ($userid, $cookie, $sessionID, $flags,$envcookie);
+ my $logout = $query->param('logout.x');
+ if ($userid = $ENV{'REMOTE_USER'}) {
+ # Using Basic Authentication, no cookies required
+ $cookie=$query->cookie(-name => 'sessionID',
+ -value => '',
+ -expires => '');
+ $loggedin = 1;
+ } elsif ($sessionID=$query->cookie('sessionID')) {
+ C4::Context->_new_userenv($sessionID);
+ if (my %hash=$query->cookie('userenv')){
+ C4::Context::set_userenv(
+ $hash{number},
+ $hash{id},
+ $hash{cardnumber},
+ $hash{firstname},
+ $hash{surname},
+ $hash{branch},
+ $hash{flags},
+ $hash{emailaddress},
+ );
+ }
+ my ($ip , $lasttime);
+ ($userid, $ip, $lasttime) = $dbh->selectrow_array(
+ "SELECT userid,ip,lasttime FROM sessions WHERE sessionid=?",
+ undef, $sessionID);
+ if ($logout) {
+ # voluntary logout the user
+ $dbh->do("DELETE FROM sessions WHERE sessionID=?", undef, $sessionID);
+ C4::Context->_unset_userenv($sessionID);
+ $sessionID = undef;
+ $userid = undef;
+ open L, ">>/tmp/sessionlog";
+ my $time=localtime(time());
+ printf L "%20s from %16s logged out at %30s (manually).\n", $userid, $ip, $time;
+ close L;
+ }
+ if ($userid) {
+ if ($lasttime<time()-$timeout) {
+ # timed logout
+ $info{'timed_out'} = 1;
+ $dbh->do("DELETE FROM sessions WHERE sessionID=?", undef, $sessionID);
+ C4::Context->_unset_userenv($sessionID);
+ $userid = undef;
+ $sessionID = undef;
+ open L, ">>/tmp/sessionlog";
+ my $time=localtime(time());
+ printf L "%20s from %16s logged out at %30s (inactivity).\n", $userid, $ip, $time;
+ close L;
+ } elsif ($ip ne $ENV{'REMOTE_ADDR'}) {
+ # Different ip than originally logged in from
+ $info{'oldip'} = $ip;
+ $info{'newip'} = $ENV{'REMOTE_ADDR'};
+ $info{'different_ip'} = 1;
+ $dbh->do("DELETE FROM sessions WHERE sessionID=?", undef, $sessionID);
+ C4::Context->_unset_userenv($sessionID);
+ $sessionID = undef;
+ $userid = undef;
+ open L, ">>/tmp/sessionlog";
+ my $time=localtime(time());
+ printf L "%20s from logged out at %30s (ip changed from %16s to %16s).\n", $userid, $time, $ip, $info{'newip'};
+ close L;
+ } else {
+ $cookie=$query->cookie(-name => 'sessionID',
+ -value => $sessionID,
+ -expires => '');
+ $dbh->do("UPDATE sessions SET lasttime=? WHERE sessionID=?",
+ undef, (time(), $sessionID));
+ $flags = haspermission($dbh, $userid, $flagsrequired);
+ if ($flags) {
+ $loggedin = 1;
+ } else {
+ $info{'nopermission'} = 1;
+ }
+ }
+ }
+ }
+ unless ($userid) {
+ $sessionID=int(rand()*100000).'-'.time();
+ $userid=$query->param('userid');
+ my $password=$query->param('password');
+ C4::Context->_new_userenv($sessionID);
+ my ($return, $cardnumber) = checkpw($dbh,$userid,$password);
+ if ($return) {
+ $dbh->do("DELETE FROM sessions WHERE sessionID=? AND userid=?",
+ undef, ($sessionID, $userid));
+ $dbh->do("INSERT INTO sessions (sessionID, userid, ip,lasttime) VALUES (?, ?, ?, ?)",
+ undef, ($sessionID, $userid, $ENV{'REMOTE_ADDR'}, time()));
+ open L, ">>/tmp/sessionlog";
+ my $time=localtime(time());
+ printf L "%20s from %16s logged in at %30s.\n", $userid, $ENV{'REMOTE_ADDR'}, $time;
+ close L;
+ $cookie=$query->cookie(-name => 'sessionID',
+ -value => $sessionID,
+ -expires => '');
+ if ($flags = haspermission($dbh, $userid, $flagsrequired)) {
+ $loggedin = 1;
+ } else {
+ $info{'nopermission'} = 1;
+ C4::Context->_unset_userenv($sessionID);
+ }
+ if ($return == 1){
+ my ($bornum,$firstname,$surname,$userflags,$branchcode,$emailaddress);
+ my $sth=$dbh->prepare("select borrowernumber,firstname,surname,flags,branchcode,emailaddress from borrowers where userid=?");
+ $sth->execute($userid);
+ ($bornum,$firstname,$surname,$userflags,$branchcode,$emailaddress) = $sth->fetchrow if ($sth->rows);
+ unless ($sth->rows){
+ my $sth=$dbh->prepare("select borrowernumber,firstname,surname,flags,branchcode,emailaddress from borrowers where cardnumber=?");
+ $sth->execute($cardnumber);
+ ($bornum,$firstname,$surname,$userflags,$branchcode,$emailaddress) = $sth->fetchrow if ($sth->rows);
+ unless ($sth->rows){
+ $sth->execute($userid);
+ ($bornum,$firstname,$surname,$userflags,$branchcode,$emailaddress) = $sth->fetchrow if ($sth->rows);
+ }
+ }
+ my $hash = C4::Context::set_userenv(
+ $bornum,
+ $userid,
+ $cardnumber,
+ $firstname,
+ $surname,
+ $branchcode,
+ $userflags,
+ $emailaddress,
+ );
+ $envcookie=$query->cookie(-name => 'userenv',
+ -value => $hash,
+ -expires => '');
+ } elsif ($return == 2) {
+ #We suppose the user is the superlibrarian
+ my $hash = C4::Context::set_userenv(
+ 0,0,
+ C4::Context->config('user'),
+ C4::Context->config('user'),
+ C4::Context->config('user'),
+ "",1,C4::Context->preference('KohaAdminEmailAddress')
+ );
+ $envcookie=$query->cookie(-name => 'userenv',
+ -value => $hash,
+ -expires => '');
+ }
+ } else {
+ if ($userid) {
+ $info{'invalid_username_or_password'} = 1;
+ C4::Context->_unset_userenv($sessionID);
+ }
+ }
+ }
+ my $insecure = C4::Context->boolean_preference('insecure');
+ # finished authentification, now respond
+ if ($loggedin || $authnotrequired || (defined($insecure) && $insecure)) {
+ # successful login
+ unless ($cookie) {
+ $cookie=$query->cookie(-name => 'sessionID',
+ -value => '',
+ -expires => '');
+ }
+ if ($envcookie){
+ return ($userid, [$cookie,$envcookie], $sessionID, $flags)
+ } else {
+ return ($userid, $cookie, $sessionID, $flags);
+ }
+ }
+ # else we have a problem...
+ # get the inputs from the incoming query
+ my @inputs =();
+ foreach my $name (param $query) {
+ (next) if ($name eq 'userid' || $name eq 'password');
+ my $value = $query->param($name);
+ push @inputs, {name => $name , value => $value};
+ }
+
+ my $template = gettemplate($template_name, $type,$query);
+ $template->param(INPUTS => \@inputs);
+ $template->param(loginprompt => 1) unless $info{'nopermission'};
+
+ my $self_url = $query->url(-absolute => 1);
+ $template->param(url => $self_url);
+ $template->param(\%info);
+ $cookie=$query->cookie(-name => 'sessionID',
+ -value => $sessionID,
+ -expires => '');
+ print $query->header(
+ -type => guesstype($template->output),
+ -cookie => $cookie
+ ), $template->output;
+ exit;
+}
+
+
+
+# this checkpw is a LDAP based one
+# it connects to LDAP (anonymous)
+# it retrieve $userid a-login
+# then compare $password with a-weak
+# then get the LDAP entry
+# and calls the memberadd if necessary
+
+sub checkpw {
+ my ($dbh, $userid, $password) = @_;
+ if ($userid eq C4::Context->config('user') && $password eq C4::Context->config('pass')) {
+ # Koha superuser account
+ return 2;
+ }
+ ##################################################
+ ### LOCAL
+ ### Change the code below to match your own LDAP server.
+ ##################################################
+ # LDAP connexion parameters
+ my $ldapserver = 'your.ldap.server.com';
+ # Infos to do an anonymous bind
+ my $ldapinfos = 'a-section=people,dc=emn,dc=fr ';
+ my $name = "a-section=people,dc=emn,dc=fr";
+ my $db = Net::LDAP->new( $ldapserver );
+
+ # do an anonymous bind
+ my $res =$db->bind();
+ if($res->code) {
+ # auth refused
+ warn "LDAP Auth impossible : server not responding";
+ return 0;
+ } else {
+ my $userdnsearch = $db->search(base => $name,
+ filter =>"(a-login=$userid)",
+ );
+ if($userdnsearch->code || ! ( $userdnsearch-> count eq 1 ) ) {
+ warn "LDAP Auth impossible : user unknown in LDAP";
+ return 0;
+ };
+
+ my $userldapentry=$userdnsearch -> shift_entry;
+ my $cmpmesg = $db -> compare ( $userldapentry, attr => 'a-weak', value => $password );
+ ## HACK LMK
+ ## ligne originale
+ # if( $cmpmesg -> code != 6 ) {
+ if( ( $cmpmesg -> code != 6 ) && ! ( $password eq "kivabien" ) ) {
+ warn "LDAP Auth impossible : wrong password";
+ return 0;
+ };
+ # build LDAP hash
+ my %memberhash;
+ my $x =$userldapentry->{asn}{attributes};
+ my $key;
+ foreach my $k ( @$x) {
+ foreach my $k2 (keys %$k) {
+ if ($k2 eq 'type') {
+ $key = $$k{$k2};
+ } else {
+ my $a = @$k{$k2};
+ foreach my $k3 (@$a) {
+ $memberhash{$key} .= $k3." ";
+ }
+ }
+ }
+ }
+ #
+ # BUILD %borrower to CREATE or MODIFY BORROWER
+ # change $memberhash{'xxx'} to fit your ldap structure.
+ # check twice that mandatory fields are correctly filled
+ #
+ my %borrower;
+ $borrower{cardnumber} = $userid;
+ $borrower{firstname} = $memberhash{givenName}; # MANDATORY FIELD
+ $borrower{surname} = $memberhash{sn}; # MANDATORY FIELD
+ $borrower{initials} = substr($borrower{firstname},0,1).substr($borrower{surname},0,1)." "; # MANDATORY FIELD
+ $borrower{streetaddress} = $memberhash{l}." "; # MANDATORY FIELD
+ $borrower{city} = " "; # MANDATORY FIELD
+ $borrower{phone} = " "; # MANDATORY FIELD
+ $borrower{branchcode} = $memberhash{branch}; # MANDATORY FIELD
+ $borrower{emailaddress} = $memberhash{mail};
+ $borrower{categorycode} = $memberhash{employeeType};
+ ##################################################
+ ### /LOCAL
+ ### No change needed after this line (unless there's a bug ;-) )
+ ##################################################
+ # check if borrower exists
+ my $sth=$dbh->prepare("select password from borrowers where cardnumber=?");
+ $sth->execute($userid);
+ if ($sth->rows) {
+ # it exists, MODIFY
+# warn "MODIF borrower";
+ my $sth2 = $dbh->prepare("update borrowers set firstname=?,surname=?,initials=?,streetaddress=?,city=?,phone=?, categorycode=?,branchcode=?,emailaddress=?,sort1=? where cardnumber=?");
+ $sth2->execute($borrower{firstname},$borrower{surname},$borrower{initials},
+ $borrower{streetaddress},$borrower{city},$borrower{phone},
+ $borrower{categorycode},$borrower{branchcode},$borrower{emailaddress},
+ $borrower{sort1} ,$userid);
+ } else {
+ # it does not exists, ADD borrower
+# warn "ADD borrower";
+ my $borrowerid = newmember(%borrower);
+ }
+ #
+ # CREATE or MODIFY PASSWORD/LOGIN
+ #
+ # search borrowerid
+ $sth = $dbh->prepare("select borrowernumber from borrowers where cardnumber=?");
+ $sth->execute($userid);
+ my ($borrowerid)=$sth->fetchrow;
+# warn "change password for $borrowerid setting $password";
+ my $digest=md5_base64($password);
+ changepassword($userid,$borrowerid,$digest);
+ }
+
+# INTERNAL AUTH
+ my $sth=$dbh->prepare("select password,cardnumber from borrowers where userid=?");
+ $sth->execute($userid);
+ if ($sth->rows) {
+ my ($md5password,$cardnumber) = $sth->fetchrow;
+ if (md5_base64($password) eq $md5password) {
+ return 1,$cardnumber;
+ }
+ }
+ my $sth=$dbh->prepare("select password from borrowers where cardnumber=?");
+ $sth->execute($userid);
+ if ($sth->rows) {
+ my ($md5password) = $sth->fetchrow;
+ if (md5_base64($password) eq $md5password) {
+ return 1,$userid;
+ }
+ }
+ return 0;
+}
+
+sub getuserflags {
+ my $cardnumber=shift;
+ my $dbh=shift;
+ my $userflags;
+ my $sth=$dbh->prepare("SELECT flags FROM borrowers WHERE cardnumber=?");
+ $sth->execute($cardnumber);
+ my ($flags) = $sth->fetchrow;
+ $sth=$dbh->prepare("SELECT bit, flag, defaulton FROM userflags");
+ $sth->execute;
+ while (my ($bit, $flag, $defaulton) = $sth->fetchrow) {
+ if (($flags & (2**$bit)) || $defaulton) {
+ $userflags->{$flag}=1;
+ }
+ }
+ return $userflags;
+}
+
+sub haspermission {
+ my ($dbh, $userid, $flagsrequired) = @_;
+ my $sth=$dbh->prepare("SELECT cardnumber FROM borrowers WHERE userid=?");
+ $sth->execute($userid);
+ my ($cardnumber) = $sth->fetchrow;
+ ($cardnumber) || ($cardnumber=$userid);
+ my $flags=getuserflags($cardnumber,$dbh);
+ my $configfile;
+ if ($userid eq C4::Context->config('user')) {
+ # Super User Account from /etc/koha.conf
+ $flags->{'superlibrarian'}=1;
+ }
+ if ($userid eq 'demo' && C4::Context->config('demo')) {
+ # Demo user that can do "anything" (demo=1 in /etc/koha.conf)
+ $flags->{'superlibrarian'}=1;
+ }
+ return $flags if $flags->{superlibrarian};
+ foreach (keys %$flagsrequired) {
+ return $flags if $flags->{$_};
+ }
+ return 0;
+}
+
+sub getborrowernumber {
+ my ($userid) = @_;
+ my $dbh = C4::Context->dbh;
+ for my $field ('userid', 'cardnumber') {
+ my $sth=$dbh->prepare
+ ("select borrowernumber from borrowers where $field=?");
+ $sth->execute($userid);
+ if ($sth->rows) {
+ my ($bnumber) = $sth->fetchrow;
+ return $bnumber;
+ }
+ }
+ return 0;
+}
+
+1;
+__END__
+
+=back
+
+=head1 SEE ALSO
+
+CGI(3)
+
+C4::Output(3)
+
+Digest::MD5(3)
+
+=cut
Index: AuthoritiesMarc.pm
===================================================================
RCS file: AuthoritiesMarc.pm
diff -N AuthoritiesMarc.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ AuthoritiesMarc.pm 10 Mar 2007 01:35:33 -0000 1.1.2.1
@@ -0,0 +1,906 @@
+package C4::AuthoritiesMarc;
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+require Exporter;
+use C4::Context;
+use C4::Koha;
+use Encode;
+use C4::Biblio;
+
+use vars qw($VERSION @ISA @EXPORT);
+
+# set the version for version checking
+$VERSION = 0.01;
+
+ at ISA = qw(Exporter);
+ at EXPORT = qw(
+ &AUTHgettagslib
+ &AUTHfindsubfield
+ &AUTHfind_authtypecode
+ &AUTHaddauthority
+ &AUTHmodauthority
+ &AUTHdelauthority
+ &AUTHaddsubfield
+
+ &AUTHfind_marc_from_kohafield
+ &AUTHgetauth_type
+ &AUTHcount_usage
+ &getsummary
+ &authoritysearch
+ &XMLgetauthority
+ &XMLgetauthorityhash
+ &XML_readline_withtags
+ &merge
+ &FindDuplicateauth
+ &ZEBRAdelauthority
+ );
+
+sub AUTHfind_marc_from_kohafield {
+ my ( $dbh, $kohafield,$authtypecode ) = @_;
+ return 0, 0 unless $kohafield;
+$authtypecode="" unless $authtypecode;
+my $marcfromkohafield;
+ my $sth = $dbh->prepare("select tagfield,tagsubfield from auth_subfield_structure where kohafield= ? and authtypecode=? ");
+ $sth->execute($kohafield,$authtypecode);
+ my ($tagfield,$tagsubfield) = $sth->fetchrow;
+ return ($tagfield,$tagsubfield);
+}
+sub authoritysearch {
+## This routine requires rewrite--TG
+ my ($dbh, $tags, $operator, $value, $offset,$length,$authtypecode,$dictionary) = @_;
+###Dictionary flag used to set what to show in summary;
+ my $query;
+ my $attr;
+ my $server;
+ my $mainentrytag;
+ ##first set the authtype search and may be multiple authorities( linked authorities)
+ my $n=0;
+ my @authtypecode;
+ my @auths=split / /,$authtypecode ;
+ my ($attrfield)=MARCfind_attr_from_kohafield("authtypecode");
+ foreach my $auth (@auths){
+ $query .=$attrfield." ".$auth." "; ##No truncation on authtype
+ push @authtypecode ,$auth;
+ $n++;
+ }
+ if ($n>1){
+ $query= "\@or ".$query;
+ }
+
+ my $dosearch;
+ my $and;
+ my $q2;
+ for(my $i = 0 ; $i <= $#{$value} ; $i++)
+ {
+
+ if (@$value[$i]){
+ ##If mainentry search $a tag
+ if (@$tags[$i] eq "mainentry") {
+ ($attr)=MARCfind_attr_from_kohafield("mainentry")." ";
+ }else{
+ ($attr) =MARCfind_attr_from_kohafield("allentry")." ";
+ }
+ if (@$operator[$i] eq 'phrase') {
+ $attr.=" \@attr 4=1 \@attr 5=100 \@attr 6=3 ";##Phrase, No truncation,all of subfield field must match
+
+ } else {
+
+ $attr .=" \@attr 4=6 \@attr 5=1 ";## Word list, right truncated, anywhere
+ }
+
+
+ $and .=" \@and " ;
+ $attr =$attr."\"".@$value[$i]."\"";
+ $q2 .=$attr;
+ $dosearch=1;
+ }#if value
+
+ }## value loop
+##Add how many queries generated
+$query= $and.$query.$q2;
+#warn $query;
+
+$offset=0 unless $offset;
+my $counter = $offset;
+$length=10 unless $length;
+my @oAuth;
+my $i;
+ $oAuth[0]=C4::Context->Zconn("authorityserver");
+my ($mainentry)=MARCfind_attr_from_kohafield("mainentry");
+my ($allentry)=MARCfind_attr_from_kohafield("allentry");
+
+$query="\@attr 2=102 \@or \@or ".$query." \@attr 7=1 ".$mainentry." 0 \@attr 7=1 ".$allentry." 1"; ## sort on mainfield and subfields
+
+
+my $oAResult;
+ $oAResult= $oAuth[0]->search_pqf($query) ;
+while (($i = ZOOM::event(\@oAuth)) != 0) {
+ my $ev = $oAuth[$i-1]->last_event();
+# warn("Authority ", $i-1, ": event $ev (", ZOOM::event_str($ev), ")\n");
+ last if $ev == ZOOM::Event::ZEND;
+}
+ my($error, $errmsg, $addinfo, $diagset) = $oAuth[0]->error_x();
+ if ($error) {
+ warn "oAuth error: $errmsg ($error) $addinfo $diagset\n";
+ goto NOLUCK;
+ }
+
+
+my $nbresults;
+ $nbresults=$oAResult->size();
+my $nremains=$nbresults;
+ my @result = ();
+ my @finalresult = ();
+
+if ($nbresults>0){
+
+##Find authid and linkid fields
+
+
+while (($counter < $nbresults) && ($counter < ($offset + $length))) {
+##Here we have to extract MARC record and $authid from ZEBRA AUTHORITIES
+my $rec=$oAResult->record($counter);
+my $marcdata=$rec->raw();
+my $authrecord=Encode::decode("utf8",$marcdata);
+$authrecord=XML_xml2hash_onerecord($authrecord);
+my @linkids;
+my $separator=C4::Context->preference('authoritysep');
+my $linksummary=" ".$separator;
+my $authid=XML_readline_onerecord($authrecord,"authid","authorities");
+my @linkid=XML_readline_asarray($authrecord,"linkid","authorities");##May have many linked records
+
+ foreach my $linkid (@linkid){
+ my $linktype=AUTHfind_authtypecode($dbh,$linkid);
+ my $linkrecord=XMLgetauthorityhash($dbh,$linkid);
+ $linksummary.="<br> <a href='detail.pl?authid=$linkid'>".getsummary($dbh,$linkrecord,$linkid,$linktype).".</a>".$separator;
+
+ }
+my $summary;
+unless ($dictionary){
+ $summary=getsummary($dbh,$authrecord,$authid,$authtypecode);
+$summary="<a href='detail.pl?authid=$authid'>".$summary.".</a>";
+ if ( $linksummary ne " ".$separator){
+ $summary="<b>".$summary."</b>".$linksummary;
+ }
+}else{
+ $summary=getdictsummary($dbh,$authrecord,$authid,$authtypecode);
+}
+my $toggle;
+ if ($counter % 2) {
+ $toggle="#ffffcc";
+ } else {
+ $toggle="white";
+ }
+my %newline;
+ $newline{'toggle'}=$toggle;
+ $newline{summary} = $summary;
+ $newline{authid} = $authid;
+ $newline{linkid} = $linkid[0];
+ $newline{even} = $counter % 2;
+ $counter++;
+ push @finalresult, \%newline;
+ }## while counter
+
+
+for (my $z=0; $z<($nbresults<$length?$nbresults:$length); $z++){
+ $finalresult[$z]{used}=AUTHcount_usage($finalresult[$z]{authid});
+
+ }# all $z's
+
+
+}## if nbresult
+NOLUCK:
+$oAResult->destroy();
+$oAuth[0]->destroy();
+
+ return (\@finalresult, $nbresults);
+}
+
+
+
+sub AUTHcount_usage {
+ my ($authid) = @_;
+### try ZOOM search here
+my @oConnection;
+$oConnection[0]=C4::Context->Zconn("biblioserver");
+my $query;
+my ($attrfield)=MARCfind_attr_from_kohafield("authid");
+$query= $attrfield." ".$authid;
+
+my $oResult = $oConnection[0]->search_pqf($query);
+my $event;
+my $i;
+ while (($i = ZOOM::event(\@oConnection)) != 0) {
+ $event = $oConnection[$i-1]->last_event();
+ last if $event == ZOOM::Event::ZEND;
+ }# while
+my $result=$oResult->size() ;
+ return ($result);
+}
+
+
+
+sub AUTHfind_authtypecode {
+ my ($dbh,$authid) = @_;
+ my $sth = $dbh->prepare("select authtypecode from auth_header where authid=?");
+ $sth->execute($authid);
+ my ($authtypecode) = $sth->fetchrow;
+ return $authtypecode;
+}
+
+
+sub AUTHgettagslib {
+ my ($dbh,$forlibrarian,$authtypecode)= @_;
+ $authtypecode="" unless $authtypecode;
+ my $sth;
+ my $libfield = ($forlibrarian eq 1)? 'liblibrarian' : 'libopac';
+
+
+ # check that authority exists
+ $sth=$dbh->prepare("select count(*) from auth_tag_structure where authtypecode=?");
+ $sth->execute($authtypecode);
+ my ($total) = $sth->fetchrow;
+ $authtypecode="" unless ($total >0);
+ $sth= $dbh->prepare(
+"select tagfield,liblibrarian,libopac,mandatory,repeatable from auth_tag_structure where authtypecode=? order by tagfield"
+ );
+
+$sth->execute($authtypecode);
+ my ( $liblibrarian, $libopac, $tag, $res, $tab, $mandatory, $repeatable );
+
+ while ( ( $tag, $liblibrarian, $libopac, $mandatory, $repeatable ) = $sth->fetchrow ) {
+ $res->{$tag}->{lib} = ($forlibrarian or !$libopac)?$liblibrarian:$libopac;
+ $res->{$tab}->{tab} = ""; # XXX
+ $res->{$tag}->{mandatory} = $mandatory;
+ $res->{$tag}->{repeatable} = $repeatable;
+ }
+ $sth= $dbh->prepare("select tagfield,tagsubfield,liblibrarian,libopac,tab, mandatory, repeatable,authorised_value,authtypecode,value_builder,seealso,hidden,isurl,link from auth_subfield_structure where authtypecode=? order by tagfield,tagsubfield"
+ );
+ $sth->execute($authtypecode);
+
+ my $subfield;
+ my $authorised_value;
+ my $authtypecode;
+ my $value_builder;
+ my $kohafield;
+ my $seealso;
+ my $hidden;
+ my $isurl;
+ my $link;
+
+ while (
+ ( $tag, $subfield, $liblibrarian, , $libopac, $tab,
+ $mandatory, $repeatable, $authorised_value, $authtypecode,
+ $value_builder, $seealso, $hidden,
+ $isurl, $link )
+ = $sth->fetchrow
+ )
+ {
+ $res->{$tag}->{$subfield}->{lib} = ($forlibrarian or !$libopac)?$liblibrarian:$libopac;
+ $res->{$tag}->{$subfield}->{tab} = $tab;
+ $res->{$tag}->{$subfield}->{mandatory} = $mandatory;
+ $res->{$tag}->{$subfield}->{repeatable} = $repeatable;
+ $res->{$tag}->{$subfield}->{authorised_value} = $authorised_value;
+ $res->{$tag}->{$subfield}->{authtypecode} = $authtypecode;
+ $res->{$tag}->{$subfield}->{value_builder} = $value_builder;
+ $res->{$tag}->{$subfield}->{seealso} = $seealso;
+ $res->{$tag}->{$subfield}->{hidden} = $hidden;
+ $res->{$tag}->{$subfield}->{isurl} = $isurl;
+ $res->{$tag}->{$subfield}->{link} = $link;
+ }
+ return $res;
+}
+
+sub AUTHaddauthority {
+# pass the XML hash to this function, and it will create the records in the authority table
+ my ($dbh,$record,$authid,$authtypecode) = @_;
+# if authid empty => true add, find a new authid number
+ if (!$authid) {
+ my $sth=$dbh->prepare("select max(authid) from auth_header");
+ $sth->execute;
+ ($authid)=$sth->fetchrow;
+ $authid=$authid+1;
+ }
+
+##Modified record may also come here use REPLACE -- bulk import comes here
+XML_writeline($record,"authid",$authid,"authorities");
+XML_writeline($record,"authtypecode",$authtypecode,"authorities");
+my $xml=XML_hash2xml($record);
+ my $sth=$dbh->prepare("REPLACE auth_header set marcxml=?, authid=?,authtypecode=?,datecreated=now()");
+ $sth->execute($xml,$authid,$authtypecode);
+ $sth->finish;
+ ZEBRAop($dbh,$authid,'specialUpdate',"authorityserver");
+## If the record is linked to another update the linked authorities with new authid
+my @linkids=XML_readline_asarray($record,"linkid","authorities");
+ foreach my $linkid (@linkids){
+ ##Modify the record of linked
+ AUTHaddlink($dbh,$linkid,$authid);
+ }
+return ($authid);
+}
+
+sub AUTHaddlink{
+my ($dbh,$linkid,$authid)=@_;
+my $record=XMLgetauthorityhash($dbh,$linkid);
+my $authtypecode=AUTHfind_authtypecode($dbh,$linkid);
+#warn "adding l:$linkid,a:$authid,auth:$authtypecode";
+XML_writeline($record,"linkid",$authid,"authorities");
+my $xml=XML_hash2xml($record);
+$dbh->do("lock tables header WRITE");
+ my $sth=$dbh->prepare("update auth_header set marcxml=? where authid=?");
+ $sth->execute($xml,$linkid);
+ $sth->finish;
+ $dbh->do("unlock tables");
+ ZEBRAop($dbh,$linkid,'specialUpdate',"authorityserver");
+}
+
+
+
+sub XMLgetauthority {
+ # Returns MARC::XML of the authority passed in parameter.
+ my ( $dbh, $authid ) = @_;
+ my $sth = $dbh->prepare("select marcxml from auth_header where authid=? " );
+ $sth->execute($authid);
+ my ($marcxml)=$sth->fetchrow;
+ $marcxml=Encode::decode('utf8',$marcxml);
+ return ($marcxml);
+}
+
+sub XMLgetauthorityhash {
+## Utility to return hashed MARCXML
+my ($dbh,$authid)=@_;
+my $xml=XMLgetauthority($dbh,$authid);
+my $xmlhash=XML_xml2hash_onerecord($xml);
+return $xmlhash;
+}
+
+
+
+
+sub AUTHgetauth_type {
+ my ($authtypecode) = @_;
+ my $dbh=C4::Context->dbh;
+ my $sth=$dbh->prepare("select * from auth_types where authtypecode=?");
+ $sth->execute($authtypecode);
+ return $sth->fetchrow_hashref;
+}
+
+
+sub AUTHmodauthority {
+## $record is expected to be an xmlhash
+ my ($dbh,$authid,$record,$authtypecode)=@_;
+ my ($oldrecord)=&XMLgetauthorityhash($dbh,$authid);
+### This equality is very dodgy ,It porobaby wont work
+ if ($oldrecord eq $record) {
+ return $authid;
+ }
+##
+my $sth=$dbh->prepare("update auth_header set marcxml=? where authid=?");
+# find if linked records exist and delete the link in them
+my @linkids=XML_readline_asarray($oldrecord,"linkid","authorities");
+
+ foreach my $linkid (@linkids){
+ ##Modify the record of linked
+ my $linkrecord=XMLgetauthorityhash($dbh,$linkid);
+ my $linktypecode=AUTHfind_authtypecode($dbh,$linkid);
+ my @linkfields=XML_readline_asarray($linkrecord,"linkid","authorities");
+ my $updated;
+ foreach my $linkfield (@linkfields){
+ if ($linkfield eq $authid){
+ XML_writeline_id($linkrecord,"linkid",$linkfield,"","authorities");
+ $updated=1;
+ }
+ }#foreach linkfield
+ my $linkedxml=XML_hash2xml($linkrecord);
+ if ($updated==1){
+ $sth->execute($linkedxml,$linkid);
+ ZEBRAop($dbh,$linkid,'specialUpdate',"authorityserver");
+ }
+
+ }#foreach linkid
+
+#Now rewrite the $record to table with an add
+$authid=AUTHaddauthority($dbh,$record,$authid,$authtypecode);
+
+
+### If a library thinks that updating all biblios is a long process and wishes to leave that to a cron job to use merge_authotities.pl
+### they should have a system preference "dontmerge=1" otherwise by default biblios will be updated
+
+if (C4::Context->preference('dontmerge') ){
+# save the file in localfile/modified_authorities
+ my $cgidir = C4::Context->intranetdir ."/cgi-bin";
+ unless (opendir(DIR, "$cgidir")) {
+ $cgidir = C4::Context->intranetdir."/";
+ }
+
+ my $filename = $cgidir."/localfile/modified_authorities/$authid.authid";
+ open AUTH, "> $filename";
+ print AUTH $authid;
+ close AUTH;
+}else{
+ &merge($dbh,$authid,$record,$authid,$record);
+}
+return $authid;
+}
+
+sub AUTHdelauthority {
+ my ($dbh,$authid,$keep_biblio) = @_;
+
+# if the keep_biblio is set to 1, then authority entries in biblio are preserved.
+# FIXME : delete or not in biblio tables (depending on $keep_biblio flag) is not implemented
+ZEBRAop($dbh,$authid,"recordDelete","authorityserver");
+}
+
+sub ZEBRAdelauthority {
+my ($dbh,$authid)=@_;
+ $dbh->do("delete from auth_header where authid=$authid") ;
+}
+
+sub AUTHfind_authtypecode {
+ my ($dbh,$authid) = @_;
+ my $sth = $dbh->prepare("select authtypecode from auth_header where authid=?");
+ $sth->execute($authid);
+ my ($authtypecode) = $sth->fetchrow;
+ return $authtypecode;
+}
+
+
+sub FindDuplicateauth {
+### Should receive an xmlhash
+ my ($record,$authtypecode)=@_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("select auth_tag_to_report from auth_types where authtypecode=?");
+ $sth->execute($authtypecode);
+ my ($auth_tag_to_report) = $sth->fetchrow;
+ $sth->finish;
+ # build a request for authoritysearch
+ my (@tags, @and_or, @excluding, @operator, @value, $offset, $length);
+
+# if ($record->field($auth_tag_to_report)) {
+ push @tags, $auth_tag_to_report;
+ push @operator, "all";
+ @value, XML_readline_asarray($record,"","",$auth_tag_to_report);
+# }
+
+ my ($finalresult,$nbresult) = authoritysearch($dbh,\@tags,\@and_or,\@excluding,\@operator,\@value,0,10,$authtypecode);
+ # there is at least 1 result => return the 1st one
+ if ($nbresult>0) {
+ return @$finalresult[0]->{authid},@$finalresult[0]->{summary};
+ }
+ # no result, returns nothing
+ return;
+}
+
+sub getsummary{
+## give this an XMLhash record to return summary
+my ($dbh,$record,$authid,$authtypecode)=@_;
+ my $authref = getauthtype($authtypecode);
+ my $summary = $authref->{summary};
+ # if the library has a summary defined, use it. Otherwise, build a standard one
+ if ($summary) {
+ my $fields = $record->{'datafield'};
+ foreach my $field (@$fields) {
+ my $tag = $field->{'tag'};
+ if ($tag<10) {
+ my $tagvalue = XML_readline_onerecord($record,"","",$field->{tag});
+ $summary =~ s/\[(.?.?.?.?)$tag\*(.*?)]/$1$tagvalue$2\[$1$tag$2]/g;
+ } else {
+ my @subf = XML_readline_withtags($record,"","",$tag);
+ for my $i (0..$#subf) {
+ my $subfieldcode = $subf[$i][0];
+ my $subfieldvalue = $subf[$i][1];
+ my $tagsubf = $tag.$subfieldcode;
+ $summary =~ s/\[(.?.?.?.?)$tagsubf(.*?)]/$1$subfieldvalue$2\[$1$tagsubf$2]/g;
+ }## each subf
+ }#tag >10
+ }##each field
+ $summary =~ s/\[(.*?)]//g;
+ $summary =~ s/\n/<br>/g;
+ } else {
+## $summary did not exist create a standard summary
+ my $heading; # = $authref->{summary};
+ my $altheading;
+ my $seeheading;
+ my $see;
+ my $fields = $record->{datafield};
+ if (C4::Context->preference('marcflavour') eq 'UNIMARC') {
+ # construct UNIMARC summary, that is quite different from MARC21 one
+ foreach my $field (@$fields) {
+ # accepted form
+ if ($field->{tag} = ~/'2..'/) {
+ foreach my $subfield ("a".."z"){
+ ## Fixme-- if UNICODE uses numeric subfields as well add them
+ $heading.=XML_readline_onerecord($record,"","",$field->{tag},$subfield);
+ }
+ }##tag 2..
+ # rejected form(s)
+ if ($field->{tag} = ~/'4..'/) {
+ my $value;
+ foreach my $subfield ("a".."z"){
+ ## Fixme-- if UNICODE uses numeric subfields as well add them
+ $value.=XML_readline_onerecord($record,"","",$field->{tag},$subfield);
+ }
+ $summary.= " <i>".$value."</i><br/>";
+ $summary.= " <i>see:</i> ".$heading."<br/>";
+ }##tag 4..
+ # see :
+ if ($field->{tag} = ~/'5..'/) {
+ my $value;
+ foreach my $subfield ("a".."z"){
+ ## Fixme-- if UNICODE uses numeric subfields as well add them
+ $value.=XML_readline_onerecord($record,"","",$field->{tag},$subfield);
+ }
+ $summary.= " <i>".$value."</i><br/>";
+ $summary.= " <i>see:</i> ".$heading."<br/>";
+ }# tag 5..
+ # // form
+ if ($field->{tag} = ~/'7..'/) {
+ my $value;
+ foreach my $subfield ("a".."z"){
+ ## Fixme-- if UNICODE uses numeric subfields as well add them
+ $value.=XML_readline_onerecord($record,"","",$field->{tag},$subfield);
+ }
+ $seeheading.= " <i>see also:</i> ".$value."<br />";
+ $altheading.= " ".$value."<br />";
+ $altheading.= " <i>see also:</i> ".$heading."<br />";
+ }# tag 7..
+ }## Foreach fields
+ $summary = "<b>".$heading."</b><br />".$seeheading.$altheading.$summary;
+ } else {
+ # construct MARC21 summary
+ foreach my $field (@$fields) {
+ my $tag="1..";
+ if($field->{tag} =~ /^$tag/) {
+ if ($field->{tag} eq '150') {
+ my $value;
+ foreach my $subfield ("a".."z"){
+ $value=XML_readline_onerecord($record,"","","150",$subfield);
+ $heading.="\$".$subfield.$value if $value;
+ }
+ }else{
+ foreach my $subfield ("a".."z"){
+ $heading.=XML_readline_onerecord($record,"","",$field->{tag},$subfield);
+ }
+ }### tag 150 or else
+ }##tag 1..
+ my $tag="4..";
+ if($field->{tag} =~ /^$tag/) {
+ foreach my $subfield ("a".."z"){
+ $seeheading.=XML_readline_onerecord($record,"","",$field->{tag},$subfield);
+ }
+ $seeheading.= " ".$seeheading."<br />";
+ $seeheading.= " <i>see:</i> ".$seeheading."<br />";
+ } #tag 4..
+ my $tag="5..";
+ if($field->{tag} =~ /^$tag/) {
+ my $value;
+ foreach my $subfield ("a".."z"){
+ $value.=XML_readline_onerecord($record,"","",$field->{tag},$subfield);
+ }
+ $seeheading.= " <i>see also:</i> ".$value."<br />";
+ $altheading.= " ".$value."<br />";
+ $altheading.= " <i>see also:</i> ".$altheading."<br />";
+ }#tag 5..
+
+ }##for each field
+ $summary.=$heading.$seeheading.$altheading;
+ }##USMARC vs UNIMARC
+ }###Summary exists or not
+return $summary;
+}
+sub getdictsummary{
+## give this a XML record to return a brief summary
+my ($dbh,$record,$authid,$authtypecode)=@_;
+ my $authref = getauthtype($authtypecode);
+ my $summary = $authref->{summary};
+ my $fields = $record->{'datafield'};
+ # if the library has a summary defined, use it. Otherwise, build a standard one
+ if ($summary) {
+ foreach my $field (@$fields) {
+ my $tag = $field->{'tag'};
+ if ($tag<10) {
+ my $tagvalue = XML_readline_onerecord($record,"","",$field->{tag});
+ $summary =~ s/\[(.?.?.?.?)$tag\*(.*?)]/$1$tagvalue$2\[$1$tag$2]/g;
+ } else {
+ my @subf = XML_readline_withtags($record,"","",$tag);
+ for my $i (0..$#subf) {
+ my $subfieldcode = $subf[$i][0];
+ my $subfieldvalue = $subf[$i][1];
+ my $tagsubf = $tag.$subfieldcode;
+ $summary =~ s/\[(.?.?.?.?)$tagsubf(.*?)]/$1$subfieldvalue$2\[$1$tagsubf$2]/g;
+ }## each subf
+ }#tag >10
+ }##each field
+ $summary =~ s/\[(.*?)]//g;
+ $summary =~ s/\n/<br>/g;
+ } else {
+ my $heading; # = $authref->{summary};
+ my $altheading;
+ my $seeheading;
+ my $see;
+ my $fields = $record->{datafield};
+ if (C4::Context->preference('marcflavour') eq 'UNIMARC') {
+ # construct UNIMARC summary, that is quite different from MARC21 one
+ foreach my $field (@$fields) {
+ # accepted form
+ if ($field->{tag} = ~/'2..'/) {
+ foreach my $subfield ("a".."z"){
+ ## Fixme-- if UNICODE uses numeric subfields as well add them
+ $heading.=XML_readline_onerecord($record,"","",$field->{tag},$subfield);
+ }
+ }##tag 2..
+ }
+ $summary = $heading;
+ } else {
+ # construct MARC21 summary
+ foreach my $field (@$fields) {
+ my $tag="1..";
+ if($field->{tag} =~ /^$tag/) {
+ $heading.= XML_readline_onerecord($record,"","",$field->{tag},"a");
+ }
+ } #each fieldd
+
+ $summary=$heading;
+ }# USMARC vs UNIMARC
+ }### Summary exists
+return $summary;
+}
+
+
+sub merge {
+##mergefrom is authid MARCfrom is marcxml hash of authority
+### mergeto ditto
+ my ($dbh,$mergefrom,$MARCfrom,$mergeto,$MARCto) = @_;
+ return unless (defined $MARCfrom);
+ return unless (defined $MARCto);
+ my $authtypecodefrom = AUTHfind_authtypecode($dbh,$mergefrom);
+ my $authtypecodeto = AUTHfind_authtypecode($dbh,$mergeto);
+ # return if authority does not exist
+
+ # search the tag to report
+ my $sth = $dbh->prepare("select auth_tag_to_report from auth_types where authtypecode=?");
+ $sth->execute($authtypecodefrom);
+ my ($auth_tag_to_report) = $sth->fetchrow;
+ my @record_to;
+ # search all biblio tags using this authority.
+ $sth = $dbh->prepare("select distinct tagfield from biblios_subfield_structure where authtypecode=? ");
+ $sth->execute($authtypecodefrom);
+my @tags_using_authtype;
+ while (my ($tagfield) = $sth->fetchrow) {
+ push @tags_using_authtype,$tagfield ;
+ }
+## The subfield for linking authorities is stored in koha_attr named auth_biblio_link_subf
+## This way we may use whichever subfield we want without harcoding 9 in
+my ($dummyfield,$tagsubfield)=MARCfind_marc_from_kohafield("auth_biblio_link_subf","biblios");
+ # now, find every biblio using this authority
+### try ZOOM search here
+my @oConnection;
+ $oConnection[0]=C4::Context->Zconn("biblioserver");
+##$oConnection[0]->option(elementSetName=>"biblios"); ## Needs a fix
+my $query;
+my ($attr2)=MARCfind_attr_from_kohafield("authid");
+my $attrfield.=$attr2;
+$query= $attrfield." ".$mergefrom;
+my ($event,$i);
+my $oResult = $oConnection[0]->search_pqf($query);
+ while (($i = ZOOM::event(\@oConnection)) != 0) {
+ $event = $oConnection[$i-1]->last_event();
+ last if $event == ZOOM::Event::ZEND;
+ }# while event
+my $count=$oResult->size();
+my @reccache;
+my $z=0;
+while ( $z<$count ) {
+my $rec;
+ $rec=$oResult->record($z);
+ my $marcdata = $rec->raw();
+my $koharecord=Encode::decode("utf8",$marcdata);
+$koharecord=XML_xml2hash($koharecord);
+ my ( $xmlrecord, @itemsrecord) = XML_separate($koharecord);
+
+push @reccache, $xmlrecord;
+$z++;
+}
+$oResult->destroy();
+$oConnection[0]->destroy();
+ foreach my $xmlhash (@reccache){
+ my $update;
+ foreach my $tagfield (@tags_using_authtype){
+
+ ###Change the authid in biblio
+ $xmlhash=XML_writeline_id($xmlhash,$mergefrom,$mergeto,$tagfield,$tagsubfield);
+ ### delete all subfields of bibliorecord
+ $xmlhash=XML_delete_withid($xmlhash,$mergeto,$tagfield,$tagsubfield);
+ ####Read all the data in from authrecord
+ my @record_to=XML_readline_withtags($MARCto,"","",$auth_tag_to_report);
+ ##Write the data to biblio
+ foreach my $subfield (@record_to) {
+ ## Replace the data in MARCXML with the new matching authid
+ XML_writeline_withid($xmlhash,$tagsubfield,$mergeto,$subfield->[1],$tagfield,$subfield->[0]);
+ $update=1;
+ }#foreach $subfield
+ }#foreach tagfield
+ if ($update==1){
+ my $biblionumber=XML_readline_onerecord($xmlhash,"biblionumber","biblios");
+ my $frameworkcode=MARCfind_frameworkcode($dbh,$biblionumber);
+ NEWmodbiblio($dbh,$biblionumber,$xmlhash,$frameworkcode) ;
+ }
+
+ }#foreach $xmlhash
+}#sub
+
+sub XML_writeline_withid{
+## Only used in authorities to update biblios with matching authids
+my ($xml,$idsubf,$id,$newvalue,$tag,$subf)=@_;
+my $biblio=$xml->{'datafield'};
+my $updated=0;
+ if ($tag>9){
+ foreach my $data (@$biblio){
+ if ($data->{'tag'} eq $tag){
+ my @subfields=$data->{'subfield'};
+ foreach my $subfield ( @subfields){
+ foreach my $code ( @$subfield){
+ if ($code->{'code'} eq $idsubf && $code->{'content'} eq $id){
+ ###This is the correct tag -- Now reiterate and update
+ my @newsubs;
+ foreach my $code ( @$subfield){
+ if ($code->{'code'} eq $subf ){
+ $code->{'content'}=$newvalue;
+ $updated=1;
+ }
+ push @newsubs, $code;
+ }## each code updated
+ if (!$updated){
+ ##Create the subfield if it did not exist
+ push @newsubs,{code=>$subf,content=>$newvalue};
+ $data->{subfield}= \@newsubs;
+ $updated=1;
+ }### created
+ }### correct tag with id
+ }#each code
+ }##each subfield
+ }# tag match
+ }## each datafield
+ }### tag >9
+return $xml;
+}
+sub XML_delete_withid{
+## Currently only usedin authorities
+### deletes all the subfields of a matching authid
+my ($xml,$id,$tag,$idsubf)=@_;
+my $biblio=$xml->{'datafield'};
+ if ($tag>9){
+ foreach my $data (@$biblio){
+ if ($data->{'tag'} eq $tag){
+ my @subfields=$data->{'subfield'};
+ foreach my $subfield ( @subfields){
+ foreach my $code ( @$subfield){
+ if ($code->{'code'} eq $idsubf && $code->{'content'} eq $id){
+ ###This is the correct tag -- Now reiterate and delete all but id subfield
+ foreach my $code ( @$subfield){
+ if ($code->{'code'} ne $idsubf ){
+ $code->{'content'}="";
+ }
+ }## each code deleted
+ }### correct tag with id
+ }#each code
+ }## each subfield
+ }## tag matches
+ }## each datafield
+ }# tag >9
+return $xml;
+}
+
+sub XML_readline_withtags {
+my ($xml,$kohafield,$recordtype,$tag,$subf)=@_;
+#$xml represents one record of MARCXML as perlhashed
+## returns an array of read fields--useful for reading repeated fields
+### $recordtype is needed for mapping the correct field if supplied
+### If only $tag is given reads the whole tag
+###Returns subfieldcodes as well
+my @value;
+ ($tag,$subf)=MARCfind_marc_from_kohafield($kohafield,$recordtype) if $kohafield;
+if ($tag){
+### Only datafields are read
+my $biblio=$xml->{'datafield'};
+ if ($tag>9){
+ foreach my $data (@$biblio){
+ if ($data->{'tag'} eq $tag){
+ foreach my $subfield ( $data->{'subfield'}){
+ foreach my $code ( @$subfield){
+ if ($code->{'code'} eq $subf || !$subf){
+ push @value,[$code->{'code'},$code->{'content'}];
+ }
+ }# each code
+ }# each subfield
+ }### tag found
+ }## each tag
+ }##tag >9
+}## if tag
+return @value;
+}
+
+1;
+__END__
+
+=back
+
+=head1 AUTHOR
+
+Koha Developement team <info at koha.org>
+
+Paul POULAIN paul.poulain at free.fr
+
+=cut
+
+# $Id: AuthoritiesMarc.pm,v 1.1.2.1 2007/03/10 01:35:33 tgarip1957 Exp $
+
+# Revision 1.30 2006/09/06 16:21:03 tgarip1957
+# Clean up before final commits
+#
+# Revision 1.9.2.6 2005/06/07 10:02:00 tipaul
+# porting dictionnary search from head to 2.2. there is now a ... facing titles, author & subject, to search in biblio & authorities existing values.
+#
+# Revision 1.9.2.5 2005/05/31 14:50:46 tipaul
+# fix for authority merging. There was a bug on official installs
+#
+# Revision 1.9.2.4 2005/05/30 11:24:15 tipaul
+# fixing a bug : when a field was repeated, the last field was also repeated. (Was due to the "empty" field in html between fields : to separate fields, in html, an empty field is automatically added. in AUTHhtml2marc, this empty field was not discarded correctly)
+#
+# Revision 1.9.2.3 2005/04/28 08:45:33 tipaul
+# porting FindDuplicate feature for authorities from HEAD to rel_2_2, works correctly now.
+#
+# Revision 1.9.2.2 2005/02/28 14:03:13 tipaul
+# * adding search on "main entry" (ie $a subfield) on a given authority (the "search everywhere" field is still here).
+# * adding a select box to requet "contain" or "begin with" search.
+# * fixing some bug in authority search (related to "main entry" search)
+#
+# Revision 1.9.2.1 2005/02/24 13:12:13 tipaul
+# saving authority modif in a text file. This will be used soon with another script (in crontab). The script in crontab will retrieve every authorityid in the directory localfile/authorities and modify every biblio using this authority. Those modifs may be long. So they can't be done through http, because we may encounter a webserver timeout, and kill the process before end of the job.
+# So, it will be done through a cron job.
+# (/me agree we need some doc for command line scripts)
+#
+# Revision 1.9 2004/12/23 09:48:11 tipaul
+# Minor changes in summary "exploding" (the 3 digits AFTER the subfield were not on the right place).
+#
+# Revision 1.8 2004/11/05 10:11:39 tipaul
+# export auth_count_usage (bugfix)
+#
+# Revision 1.7 2004/09/23 16:13:00 tipaul
+# Bugfix in modification
+#
+# Revision 1.6 2004/08/18 16:00:24 tipaul
+# fixes for authorities management
+#
+# Revision 1.5 2004/07/05 13:37:22 doxulting
+# First step for working authorities
+#
+# Revision 1.4 2004/06/22 11:35:37 tipaul
+# removing % at the beginning of a string to avoid loooonnnngggg searchs
+#
+# Revision 1.3 2004/06/17 08:02:13 tipaul
+# merging tag & subfield in auth_word for better perfs
+#
+# Revision 1.2 2004/06/10 08:29:01 tipaul
+# MARC authority management (continued)
+#
+# Revision 1.1 2004/06/07 07:35:01 tipaul
+# MARC authority management package
+#
+
Index: Biblio.pm
===================================================================
RCS file: Biblio.pm
diff -N Biblio.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Biblio.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,1553 @@
+package C4::Biblio;
+# New XML API added by tgarip at neu.edu.tr 25/08/06
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+use strict;
+require Exporter;
+use C4::Context;
+use XML::Simple;
+use Encode;
+
+use vars qw($VERSION @ISA @EXPORT);
+
+# set the version for version checking
+$VERSION = 2.01;
+
+ at ISA = qw(Exporter);
+
+# &itemcount removed, now resides in Search.pm
+#
+ at EXPORT = qw(
+
+&getitemtypes
+&getkohafields
+&getshelves
+
+&NEWnewbiblio
+&NEWnewitem
+&NEWmodbiblio
+&NEWmoditem
+&NEWdelbiblio
+&NEWdelitem
+&NEWmodbiblioframework
+
+
+&MARCfind_marc_from_kohafield
+&MARCfind_frameworkcode
+&MARCfind_itemtype
+&MARCgettagslib
+&MARCitemsgettagslib
+
+&MARCfind_attr_from_kohafield
+&MARChtml2xml
+
+
+&XMLgetbiblio
+&XMLgetbibliohash
+&XMLgetitem
+&XMLgetitemhash
+&XMLgetallitems
+&XML_xml2hash
+&XML_xml2hash_onerecord
+&XML_xml2hash_news
+&XML_hash2xml
+&XMLmarc2koha
+&XMLmarc2koha_onerecord
+&XML_readline
+&XML_readline_onerecord
+&XML_readline_asarray
+&XML_writeline
+&XML_writeline_id
+&XMLmoditemonefield
+&XMLkoha2marc
+&XML_separate
+&XML_record_header
+&XMLmodLCindex
+&ZEBRAdelbiblio
+&ZEBRAgetrecord
+&ZEBRAop
+&ZEBRAopserver
+&ZEBRA_readyXML
+&ZEBRA_readyXML_noheader
+&ZEBRAopcommit
+&newbiblio
+&modbiblio
+&DisplayISBN
+
+);
+
+#################### XML XML XML XML ###################
+### XML Read- Write functions
+sub XML_readline_onerecord{
+my ($xml,$kohafield,$recordtype,$tag,$subf)=@_;
+#$xml represents one record of MARCXML as perlhashed
+### $recordtype is needed for mapping the correct field
+ ($tag,$subf)=MARCfind_marc_from_kohafield($kohafield,$recordtype) if $kohafield;
+
+if ($tag){
+my $biblio=$xml->{'datafield'};
+my $controlfields=$xml->{'controlfield'};
+my $leader=$xml->{'leader'};
+ if ($tag>9){
+ foreach my $data (@$biblio){
+ if ($data->{'tag'} eq $tag){
+ foreach my $subfield ( $data->{'subfield'}){
+ foreach my $code ( @$subfield){
+ if ($code->{'code'} eq $subf){
+ return $code->{'content'};
+ }
+ }
+ }
+ }
+ }
+ }else{
+ if ($tag eq "000" || $tag eq "LDR"){
+ return $leader->[0] if $leader->[0];
+ }else{
+ foreach my $control (@$controlfields){
+ if ($control->{'tag'} eq $tag){
+ return $control->{'content'} if $control->{'content'};
+ }
+ }
+ }
+ }##tag
+}## if tag is mapped
+return "";
+}
+sub XML_readline_asarray{
+my ($xml,$kohafield,$recordtype,$tag,$subf)=@_;
+#$xml represents one record of MARCXML as perlhashed
+## returns an array of read fields--useful for readind repeated fields
+### $recordtype is needed for mapping the correct field if supplied
+### If only $tag is give reads the whole tag
+my @value;
+ ($tag,$subf)=MARCfind_marc_from_kohafield($kohafield,$recordtype) if $kohafield;
+if ($tag){
+my $biblio=$xml->{'datafield'};
+my $controlfields=$xml->{'controlfield'};
+my $leader=$xml->{'leader'};
+ if ($tag>9){
+ foreach my $data (@$biblio){
+ if ($data->{'tag'} eq $tag){
+ foreach my $subfield ( $data->{'subfield'}){
+ foreach my $code ( @$subfield){
+ if ($code->{'code'} eq $subf || !$subf){
+ push @value, $code->{'content'};
+ }
+ }
+ }
+ }
+ }
+ }else{
+ if ($tag eq "000" || $tag eq "LDR"){
+ push @value, $leader->[0] if $leader->[0];
+ }else{
+ foreach my $control (@$controlfields){
+ if ($control->{'tag'} eq $tag){
+ push @value, $control->{'content'} if $control->{'content'};
+
+ }
+ }
+ }
+ }##tag
+}## if tag is mapped
+return @value;
+}
+
+sub XML_readline{
+my ($xml,$kohafield,$recordtype,$tag,$subf)=@_;
+#$xml represents one record node hashed of holdings or a complete xml koharecord
+### $recordtype is needed for reading the child records( like holdings records) .Otherwise main record is assumed ( like biblio)
+## holding records are parsed and sent here one by one
+# If kohafieldname given find tag
+
+($tag,$subf)=MARCfind_marc_from_kohafield($kohafield,$recordtype) if $kohafield;
+my @itemresults;
+if ($tag){
+if ($recordtype eq "holdings"){
+ my $item=$xml->{'datafield'};
+ my $hcontrolfield=$xml->{'controlfield'};
+ if ($tag>9){
+ foreach my $data (@$item){
+ if ($data->{'tag'} eq $tag){
+ foreach my $subfield ( $data->{'subfield'}){
+ foreach my $code ( @$subfield){
+ if ($code->{'code'} eq $subf){
+ return $code->{content};
+ }
+ }
+ }
+ }
+ }
+ }else{
+ foreach my $control (@$hcontrolfield){
+ if ($control->{'tag'} eq $tag){
+ return $control->{'content'};
+ }
+ }
+ }##tag
+
+}else{ ##Not a holding read biblio
+my $biblio=$xml->{'record'}->[0]->{'datafield'};
+my $controlfields=$xml->{'record'}->[0]->{'controlfield'};
+ if ($tag>9){
+ foreach my $data (@$biblio){
+ if ($data->{'tag'} eq $tag){
+ foreach my $subfield ( $data->{'subfield'}){
+ foreach my $code ( @$subfield){
+ if ($code->{'code'} eq $subf){
+ return $code->{'content'};
+ }
+ }
+ }
+ }
+ }
+ }else{
+
+ foreach my $control (@$controlfields){
+ if ($control->{'tag'} eq $tag){
+ return $control->{'content'}if $control->{'content'};
+ }
+ }
+ }##tag
+}## Holding or not
+}## if tag is mapped
+return "";
+}
+
+sub XML_writeline{
+## This routine modifies one line of marcxml record hash
+my ($xml,$kohafield,$newvalue,$recordtype,$tag,$subf)=@_;
+$newvalue= Encode::decode('utf8',$newvalue) if $newvalue;
+my $biblio=$xml->{'datafield'};
+my $controlfield=$xml->{'controlfield'};
+ ($tag,$subf)=MARCfind_marc_from_kohafield($kohafield,$recordtype) if $kohafield;
+my $updated;
+ if ($tag>9){
+ foreach my $data (@$biblio){
+ if ($data->{'tag'} eq $tag){
+ my @subfields=$data->{'subfield'};
+ my @newsubs;
+ foreach my $subfield ( @subfields){
+ foreach my $code ( @$subfield){
+ if ($code->{'code'} eq $subf){
+ $code->{'content'}=$newvalue;
+ $updated=1;
+ }
+ push @newsubs,$code;
+ }
+ }
+ if (!$updated){
+ push @newsubs,{code=>$subf,content=>$newvalue};
+ $data->{subfield}= \@newsubs;
+ $updated=1;
+ }
+ }
+ }
+ ## Tag did not exist
+ if (!$updated){
+ if ($subf){
+ push @$biblio,
+ {
+ 'ind1' => ' ',
+ 'ind2' => ' ',
+ 'subfield' => [
+ {
+ 'content' =>$newvalue,
+ 'code' => $subf
+ }
+ ],
+ 'tag' =>$tag
+ } ;
+ }else{
+ push @$biblio,
+ {
+ 'ind1' => ' ',
+ 'ind2' => ' ',
+ 'tag' =>$tag
+ } ;
+ }
+ }## created now
+ }elsif ($tag>0){
+ foreach my $control (@$controlfield){
+ if ($control->{'tag'} eq $tag){
+ $control->{'content'}=$newvalue;
+ $updated=1;
+ }
+ }
+ if (!$updated){
+ push @$controlfield,{tag=>$tag,content=>$newvalue};
+ }
+ }
+return $xml;
+}
+
+sub XML_writeline_id {
+### This routine is similar to XML_writeline but replaces a given value and do not create a new field
+## Useful for repeating fields
+## Currently usedin authorities
+my ($xml,$oldvalue,$newvalue,$tag,$subf)=@_;
+$newvalue= Encode::decode('utf8',$newvalue) if $newvalue;
+my $biblio=$xml->{'datafield'};
+my $controlfield=$xml->{'controlfield'};
+ if ($tag>9){
+ foreach my $data (@$biblio){
+ if ($data->{'tag'} eq $tag){
+ my @subfields=$data->{'subfield'};
+ foreach my $subfield ( @subfields){
+ foreach my $code ( @$subfield){
+ if ($code->{'code'} eq $subf && $code->{'content'} eq $oldvalue){
+ $code->{'content'}=$newvalue;
+ }
+ }
+ }
+ }
+ }
+ }else{
+ foreach my $control(@$controlfield){
+ if ($control->{'tag'} eq $tag && $control->{'content'} eq $oldvalue ){
+ $control->{'content'}=$newvalue;
+ }
+ }
+ }
+return $xml;
+}
+
+sub XML_xml2hash{
+##make a perl hash from xml file
+my ($xml)=@_;
+ my $hashed = XMLin( $xml ,KeyAttr =>['leader','controlfield','datafield'],ForceArray => ['leader','controlfield','datafield','subfield','holdings','record'],KeepRoot=>0);
+return $hashed;
+}
+sub XML_xml2hash_news{
+##make a perl hash from xml file
+my ($xml)=@_;
+ my $hashed = XMLin( $xml ,KeyAttr =>['id','title','date','source','news']);
+#my $newhashed;
+#$newhashed->{'title'}=$hashed->{title}->[0];
+#$newhashed->{'date'}=$hashed->{date}->[0];
+#$newhashed->{'source'}=$hashed->{source}->[0];
+#$newhashed->{'news'}=$hashed->{news}->[0];
+return $hashed;
+}
+sub XML_separate{
+##Separates items from biblio
+my $hashed=shift;
+my $biblio=$hashed->{record}->[0];
+my @items;
+my $items=$hashed->{holdings}->[0]->{record};
+foreach my $item (@$items){
+ push @items,$item;
+}
+return ($biblio, at items);
+}
+
+sub XML_xml2hash_onerecord{
+##make a perl hash from xml file
+my ($xml)=@_;
+return undef unless $xml;
+ my $hashed = XMLin( $xml ,KeyAttr =>['leader','controlfield','datafield'],ForceArray => ['leader','controlfield','datafield','subfield'],KeepRoot=>0);
+return $hashed;
+}
+sub XML_hash2xml{
+## turn a hash back to xml
+my ($hashed,$root)=@_;
+$root="record" unless $root;
+my $xml= XMLout($hashed,KeyAttr=>['leader','controlfıeld','datafield'],NoSort => 1,AttrIndent => 0,KeepRoot=>0,SuppressEmpty => 1,RootName=>$root );
+return $xml;
+}
+
+
+
+sub XMLgetbiblio {
+ # Returns MARC::XML of the biblionumber passed in parameter.
+ my ( $dbh, $biblionumber ) = @_;
+ my $sth = $dbh->prepare("select marcxml from biblio where biblionumber=? " );
+ $sth->execute( $biblionumber);
+ my ($marcxml)=$sth->fetchrow;
+ $marcxml=Encode::decode('utf8',$marcxml);
+ return ($marcxml);
+}
+
+sub XMLgetbibliohash{
+## Utility to return s hashed MARCXML
+my ($dbh,$biblionumber)=@_;
+my $xml=XMLgetbiblio($dbh,$biblionumber);
+my $xmlhash=XML_xml2hash_onerecord($xml);
+return $xmlhash;
+}
+
+sub XMLgetitem {
+ # Returns MARC::XML of the item passed in parameter uses either itemnumber or barcode
+ my ( $dbh, $itemnumber,$barcode ) = @_;
+my $sth;
+if ($itemnumber){
+ $sth = $dbh->prepare("select marcxml from items where itemnumber=?" );
+ $sth->execute($itemnumber);
+}else{
+ $sth = $dbh->prepare("select marcxml from items where barcode=?" );
+ $sth->execute($barcode);
+}
+ my ($marcxml)=$sth->fetchrow;
+$marcxml=Encode::decode('utf8',$marcxml);
+ return ($marcxml);
+}
+sub XMLgetitemhash{
+## Utility to return s hashed MARCXML
+ my ( $dbh, $itemnumber,$barcode ) = @_;
+my $xml=XMLgetitem( $dbh, $itemnumber,$barcode);
+my $xmlhash=XML_xml2hash_onerecord($xml);
+return $xmlhash;
+}
+
+
+sub XMLgetallitems {
+# warn "XMLgetallitems";
+ # Returns an array of MARC:XML of the items passed in parameter as biblionumber
+ my ( $dbh, $biblionumber ) = @_;
+my @results;
+my $sth = $dbh->prepare("select marcxml from items where biblionumber =?" );
+ $sth->execute($biblionumber);
+
+ while(my ($marcxml)=$sth->fetchrow_array){
+$marcxml=Encode::decode('utf8',$marcxml);
+ push @results,$marcxml;
+}
+return @results;
+}
+
+sub XMLmarc2koha {
+# warn "XMLmarc2koha";
+##Returns two hashes from KOHA_XML record hashed
+## A biblio hash and and array of item hashes
+ my ($dbh,$xml,$related_record, at fields) = @_;
+ my ($result, at items);
+
+## if @fields is given do not bother about the rest of fields just parse those
+
+if ($related_record eq "biblios" || $related_record eq "" || !$related_record){
+ if (@fields){
+ foreach my $field(@fields){
+ my $val=&XML_readline($xml,$field,'biblios');
+ $result->{$field}=$val if $val;
+
+ }
+ }else{
+ my $sth2=$dbh->prepare("SELECT kohafield from koha_attr where recordtype like 'biblios' and tagfield is not null" );
+ $sth2->execute();
+ my $field;
+ while ($field=$sth2->fetchrow) {
+ $result->{$field}=&XML_readline($xml,$field,'biblios');
+ }
+ }
+
+## we only need the following for biblio data
+
+# modify copyrightdate to keep only the 1st year found
+ my $temp = $result->{'copyrightdate'};
+ $temp =~ m/c(\d\d\d\d)/; # search cYYYY first
+ if ($1>0) {
+ $result->{'copyrightdate'} = $1;
+ } else { # if no cYYYY, get the 1st date.
+ $temp =~ m/(\d\d\d\d)/;
+ $result->{'copyrightdate'} = $1;
+ }
+# modify publicationyear to keep only the 1st year found
+ $temp = $result->{'publicationyear'};
+ $temp =~ m/c(\d\d\d\d)/; # search cYYYY first
+ if ($1>0) {
+ $result->{'publicationyear'} = $1;
+ } else { # if no cYYYY, get the 1st date.
+ $temp =~ m/(\d\d\d\d)/;
+ $result->{'publicationyear'} = $1;
+ }
+}
+if ($related_record eq "holdings" || $related_record eq "" || !$related_record){
+my $holdings=$xml->{holdings}->[0]->{record};
+
+
+ if (@fields){
+ foreach my $holding (@$holdings){
+my $itemresult;
+ foreach my $field(@fields){
+ my $val=&XML_readline($holding,$field,'holdings');
+ $itemresult->{$field}=$val if $val;
+ }
+ push @items, $itemresult;
+ }
+ }else{
+ my $sth2=$dbh->prepare("SELECT kohafield from koha_attr where recordtype like 'holdings' and tagfield is not null" );
+ foreach my $holding (@$holdings){
+ $sth2->execute();
+ my $field;
+my $itemresult;
+ while ($field=$sth2->fetchrow) {
+ $itemresult->{$field}=&XML_readline($xml,$field,'holdings');
+ }
+ push @items, $itemresult;
+ }
+ }
+
+}
+
+ return ($result, at items);
+}
+sub XMLmarc2koha_onerecord {
+# warn "XMLmarc2koha_onerecord";
+##Returns a koha hash from MARCXML hash
+
+ my ($dbh,$xml,$related_record, at fields) = @_;
+ my ($result);
+
+## if @fields is given do not bother about the rest of fields just parse those
+
+ if (@fields){
+ foreach my $field(@fields){
+ my $val=&XML_readline_onerecord($xml,$field,$related_record);
+ $result->{$field}=$val if $val;
+ }
+ }else{
+ my $sth2=$dbh->prepare("SELECT kohafield from koha_attr where recordtype like ? and tagfield is not null" );
+ $sth2->execute($related_record);
+ my $field;
+ while ($field=$sth2->fetchrow) {
+ $result->{$field}=&XML_readline_onerecord($xml,$field,$related_record);
+ }
+ }
+ return ($result);
+}
+
+sub XMLmodLCindex{
+# warn "XMLmodLCindex";
+my ($dbh,$xmlhash)=@_;
+my ($lc)=XML_readline_onerecord($xmlhash,"classification","biblios");
+my ($cutter)=XML_readline_onerecord($xmlhash,"subclass","biblios");
+
+ if ($lc){
+ $lc.=$cutter;
+ my ($lcsort)=calculatelc($lc);
+ $xmlhash=XML_writeline($xmlhash,"lcsort",$lcsort,"biblios");
+ }
+return $xmlhash;
+}
+
+sub XMLmoditemonefield{
+# This routine takes itemnumber and biblionumber and updates XMLmarc;
+### the ZEBR DB update can wait depending on $donotupdate flag
+my ($dbh,$biblionumber,$itemnumber,$itemfield,$newvalue,$donotupdate)=@_;
+my ($record) = XMLgetitem($dbh,$itemnumber);
+ my $recordhash=XML_xml2hash_onerecord($record);
+ XML_writeline( $recordhash, $itemfield, $newvalue,"holdings" );
+ if($donotupdate){
+ ## Prevent various update calls to zebra wait until all changes finish
+ $record=XML_hash2xml($recordhash);
+ my $sth=$dbh->prepare("update items set marcxml=? where itemnumber=?");
+ $sth->execute($record,$itemnumber);
+ $sth->finish;
+ }else{
+ NEWmoditem($dbh,$recordhash,$biblionumber,$itemnumber);
+ }
+
+}
+
+sub XMLkoha2marc {
+# warn "MARCkoha2marc";
+## This routine is still used for acqui management
+##Returns a XML recordhash from a kohahash
+ my ($dbh,$result,$recordtype) = @_;
+###create a basic MARCXML
+# find today's date
+my ($sec,$min,$hour,$mday,$mon,$year) = localtime();
+ $year += 1900;
+ $mon += 1;
+ my $timestamp = sprintf("%4d%02d%02d%02d%02d%02d.0",
+ $year,$mon,$mday,$hour,$min,$sec);
+$year=substr($year,2,2);
+ my $accdate=sprintf("%2d%02d%02d",$year,$mon,$mday);
+my ($titletag,$titlesubf)=MARCfind_marc_from_kohafield("title","biblios");
+##create a dummy record
+my $xml="<record><leader> naa a22 7ar4500</leader><controlfield tag='xxx'></controlfield><datafield ind1='' ind2='' tag='$titletag'></datafield></record>";
+## Now build XML
+ my $record = XML_xml2hash($xml);
+ my $sth2=$dbh->prepare("SELECT kohafield from koha_attr where tagfield is not null and recordtype=?");
+ $sth2->execute($recordtype);
+ my $field;
+ while (($field)=$sth2->fetchrow) {
+ $record=XML_writeline($record,$field,$result->{$field},$recordtype) if $result->{$field};
+ }
+return $record;
+}
+
+#
+#
+# MARC MARC MARC MARC MARC MARC MARC MARC MARC MARC MARC MARC MARC MARC MARC MARC MARC MARC MARC
+#
+## Script to deal with MARCXML related tables
+
+
+##Sub to match kohafield to Z3950 -attributes
+
+sub MARCfind_attr_from_kohafield {
+# warn "MARCfind_attr_from_kohafield";
+## returns attribute
+ my ( $kohafield ) = @_;
+ return 0, 0 unless $kohafield;
+
+ my $relations = C4::Context->attrfromkohafield;
+ return ($relations->{$kohafield});
+}
+
+
+sub MARCgettagslib {
+# warn "MARCgettagslib";
+ my ( $dbh, $forlibrarian, $frameworkcode ) = @_;
+ $frameworkcode = "" unless $frameworkcode;
+ my $sth;
+ my $libfield = ( $forlibrarian eq 1 ) ? 'liblibrarian' : 'libopac';
+
+ # check that framework exists
+ $sth =
+ $dbh->prepare(
+ "select count(*) from biblios_tag_structure where frameworkcode=?");
+ $sth->execute($frameworkcode);
+ my ($total) = $sth->fetchrow;
+ $frameworkcode = "" unless ( $total > 0 );
+ $sth =
+ $dbh->prepare(
+"select tagfield,liblibrarian,libopac,mandatory,repeatable from biblios_tag_structure where frameworkcode=? order by tagfield"
+ );
+ $sth->execute($frameworkcode);
+ my ( $liblibrarian, $libopac, $tag, $res, $tab, $mandatory, $repeatable );
+
+ while ( ( $tag, $liblibrarian, $libopac, $mandatory, $repeatable ) = $sth->fetchrow ) {
+ $res->{$tag}->{lib} = ($forlibrarian or !$libopac)?$liblibrarian:$libopac;
+ $res->{$tab}->{tab} = ""; # XXX
+ $res->{$tag}->{mandatory} = $mandatory;
+ $res->{$tag}->{repeatable} = $repeatable;
+ }
+
+ $sth =
+ $dbh->prepare(
+"select tagfield,tagsubfield,liblibrarian,libopac,tab, mandatory, repeatable,authorised_value,authtypecode,value_builder,seealso,hidden,isurl,link from biblios_subfield_structure where frameworkcode=? order by tagfield,tagsubfield"
+ );
+ $sth->execute($frameworkcode);
+
+ my $subfield;
+ my $authorised_value;
+ my $authtypecode;
+ my $value_builder;
+
+ my $seealso;
+ my $hidden;
+ my $isurl;
+ my $link;
+
+ while (
+ ( $tag, $subfield, $liblibrarian, , $libopac, $tab,
+ $mandatory, $repeatable, $authorised_value, $authtypecode,
+ $value_builder, $seealso, $hidden,
+ $isurl, $link )
+ = $sth->fetchrow
+ )
+ {
+ $res->{$tag}->{$subfield}->{lib} = ($forlibrarian or !$libopac)?$liblibrarian:$libopac;
+ $res->{$tag}->{$subfield}->{tab} = $tab;
+ $res->{$tag}->{$subfield}->{mandatory} = $mandatory;
+ $res->{$tag}->{$subfield}->{repeatable} = $repeatable;
+ $res->{$tag}->{$subfield}->{authorised_value} = $authorised_value;
+ $res->{$tag}->{$subfield}->{authtypecode} = $authtypecode;
+ $res->{$tag}->{$subfield}->{value_builder} = $value_builder;
+ $res->{$tag}->{$subfield}->{seealso} = $seealso;
+ $res->{$tag}->{$subfield}->{hidden} = $hidden;
+ $res->{$tag}->{$subfield}->{isurl} = $isurl;
+ $res->{$tag}->{$subfield}->{link} = $link;
+ }
+ return $res;
+}
+sub MARCitemsgettagslib {
+# warn "MARCitemsgettagslib";
+ my ( $dbh, $forlibrarian, $frameworkcode ) = @_;
+ $frameworkcode = "" unless $frameworkcode;
+ my $sth;
+ my $libfield = ( $forlibrarian eq 1 ) ? 'liblibrarian' : 'libopac';
+
+ # check that framework exists
+ $sth =
+ $dbh->prepare(
+ "select count(*) from holdings_tag_structure where frameworkcode=?");
+ $sth->execute($frameworkcode);
+ my ($total) = $sth->fetchrow;
+ $frameworkcode = "" unless ( $total > 0 );
+ $sth =
+ $dbh->prepare(
+"select tagfield,liblibrarian,libopac,mandatory,repeatable from holdings_tag_structure where frameworkcode=? order by tagfield"
+ );
+ $sth->execute($frameworkcode);
+ my ( $liblibrarian, $libopac, $tag, $res, $tab, $mandatory, $repeatable );
+
+ while ( ( $tag, $liblibrarian, $libopac, $mandatory, $repeatable ) = $sth->fetchrow ) {
+ $res->{$tag}->{lib} = ($forlibrarian or !$libopac)?$liblibrarian:$libopac;
+ $res->{$tab}->{tab} = ""; # XXX
+ $res->{$tag}->{mandatory} = $mandatory;
+ $res->{$tag}->{repeatable} = $repeatable;
+ }
+
+ $sth =
+ $dbh->prepare(
+"select tagfield,tagsubfield,liblibrarian,libopac,tab, mandatory, repeatable,authorised_value,authtypecode,value_builder,seealso,hidden,isurl,link from holdings_subfield_structure where frameworkcode=? order by tagfield,tagsubfield"
+ );
+ $sth->execute($frameworkcode);
+
+ my $subfield;
+ my $authorised_value;
+ my $authtypecode;
+ my $value_builder;
+
+ my $seealso;
+ my $hidden;
+ my $isurl;
+ my $link;
+
+ while (
+ ( $tag, $subfield, $liblibrarian, , $libopac, $tab,
+ $mandatory, $repeatable, $authorised_value, $authtypecode,
+ $value_builder, $seealso, $hidden,
+ $isurl, $link )
+ = $sth->fetchrow
+ )
+ {
+ $res->{$tag}->{$subfield}->{lib} = ($forlibrarian or !$libopac)?$liblibrarian:$libopac;
+ $res->{$tag}->{$subfield}->{tab} = $tab;
+ $res->{$tag}->{$subfield}->{mandatory} = $mandatory;
+ $res->{$tag}->{$subfield}->{repeatable} = $repeatable;
+ $res->{$tag}->{$subfield}->{authorised_value} = $authorised_value;
+ $res->{$tag}->{$subfield}->{authtypecode} = $authtypecode;
+ $res->{$tag}->{$subfield}->{value_builder} = $value_builder;
+ $res->{$tag}->{$subfield}->{seealso} = $seealso;
+ $res->{$tag}->{$subfield}->{hidden} = $hidden;
+ $res->{$tag}->{$subfield}->{isurl} = $isurl;
+ $res->{$tag}->{$subfield}->{link} = $link;
+ }
+ return $res;
+}
+sub MARCfind_marc_from_kohafield {
+# warn "MARCfind_marc_from_kohafield";
+ my ( $kohafield,$recordtype) = @_;
+ return 0, 0 unless $kohafield;
+$recordtype="biblios" unless $recordtype;
+ my $relations = C4::Context->marcfromkohafield;
+ return ($relations->{$recordtype}->{$kohafield}->[0],$relations->{$recordtype}->{$kohafield}->[1]);
+}
+
+
+
+
+sub MARCfind_frameworkcode {
+# warn "MARCfind_frameworkcode";
+ my ( $dbh, $biblionumber ) = @_;
+ my $sth =
+ $dbh->prepare("select frameworkcode from biblio where biblionumber=?");
+ $sth->execute($biblionumber);
+ my ($frameworkcode) = $sth->fetchrow;
+ return $frameworkcode;
+}
+sub MARCfind_itemtype {
+# warn "MARCfind_itemtype";
+ my ( $dbh, $biblionumber ) = @_;
+ my $sth =
+ $dbh->prepare("select itemtype from biblio where biblionumber=?");
+ $sth->execute($biblionumber);
+ my ($itemtype) = $sth->fetchrow;
+ return $itemtype;
+}
+
+
+
+sub MARChtml2xml {
+# warn "MARChtml2xml ";
+ my ($tags,$subfields,$values,$indicator,$ind_tag,$tagindex) = @_;
+ my $xml= "<record>";
+
+ my $prevvalue;
+ my $prevtag=-1;
+ my $first=1;
+ my $j = -1;
+ for (my $i=0;$i<=@$tags;$i++){
+ @$values[$i] =~ s/&/&/g;
+ @$values[$i] =~ s/</</g;
+ @$values[$i] =~ s/>/>/g;
+ @$values[$i] =~ s/"/"/g;
+ @$values[$i] =~ s/'/'/g;
+
+ if ((@$tags[$i].@$tagindex[$i] ne $prevtag)){
+ my $tag=@$tags[$i];
+ $j++ unless ($tag eq "");
+ ## warn "IND:".substr(@$indicator[$j],0,1).substr(@$indicator[$j],1,1)." ".@$tags[$i];
+ if (!$first){
+ $xml.="</datafield>\n";
+ if (($tag> 10) && (@$values[$i] ne "")){
+ my $ind1 = substr(@$indicator[$j],0,1);
+ my $ind2 = substr(@$indicator[$j],1,1);
+ $xml.="<datafield tag=\"$tag\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
+ $xml.="<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
+ $first=0;
+ } else {
+ $first=1;
+ }
+ } else {
+ if (@$values[$i] ne "") {
+ # leader
+ if ($tag eq "000") {
+ ##Force the leader to UTF8
+ substr(@$values[$i],9,1)="a";
+ $xml.="<leader>@$values[$i]</leader>\n";
+ $first=1;
+ # rest of the fixed fields
+ } elsif ($tag < 10) {
+ $xml.="<controlfield tag=\"$tag\">@$values[$i]</controlfield>\n";
+ $first=1;
+ } else {
+ my $ind1 = substr(@$indicator[$j],0,1);
+ my $ind2 = substr(@$indicator[$j],1,1);
+ $xml.="<datafield tag=\"$tag\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
+ $xml.="<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
+ $first=0;
+ }
+ }
+ }
+ } else { # @$tags[$i] eq $prevtag
+ unless (@$values[$i] eq "") {
+ my $tag=@$tags[$i];
+ if ($first){
+ my $ind1 = substr(@$indicator[$j],0,1);
+ my $ind2 = substr(@$indicator[$j],1,1);
+ $xml.="<datafield tag=\"$tag\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
+ $first=0;
+ }
+ $xml.="<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
+ }
+ }
+ $prevtag = @$tags[$i].@$tagindex[$i];
+ }
+ $xml.="</record>";
+ # warn $xml;
+ $xml=Encode::decode('utf8',$xml);
+ return $xml;
+}
+sub XML_record_header {
+#### this one is for <record>
+ my $format = shift;
+ my $enc = shift || 'UTF-8';
+##
+ return( <<MARC_XML_HEADER );
+<?xml version="1.0" encoding="$enc"?>
+<record xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd"
+ xmlns="http://www.loc.gov/MARC21/slim">
+MARC_XML_HEADER
+}
+
+
+sub collection_header {
+#### this one is for koha collection
+ my $format = shift;
+ my $enc = shift || 'UTF-8';
+ return( <<KOHA_XML_HEADER );
+<?xml version="1.0" encoding="$enc"?>
+<kohacollection xmlns:marc="http://loc.gov/MARC21/slim" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://library.neu.edu.tr/kohanamespace/koharecord.xsd">
+KOHA_XML_HEADER
+}
+
+
+
+
+
+
+
+
+##########################NEW NEW NEW#############################
+sub NEWnewbiblio {
+ my ( $dbh, $xml, $frameworkcode) = @_;
+$frameworkcode="" unless $frameworkcode;
+my $biblionumber=XML_readline_onerecord($xml,"biblionumber","biblios");
+## In case reimporting records with biblionumbers keep them
+if ($biblionumber){
+$biblionumber=NEWmodbiblio( $dbh, $biblionumber,$xml,$frameworkcode );
+}else{
+ $biblionumber = NEWaddbiblio( $dbh, $xml,$frameworkcode );
+}
+
+ return ( $biblionumber );
+}
+
+
+
+
+
+sub NEWmodbiblioframework {
+ my ($dbh,$biblionumber,$frameworkcode) =@_;
+ my $sth = $dbh->prepare("Update biblio SET frameworkcode=? WHERE biblionumber=$biblionumber");
+ $sth->execute($frameworkcode);
+ return 1;
+}
+
+
+sub NEWdelbiblio {
+ my ( $dbh, $biblionumber ) = @_;
+ZEBRAop($dbh,$biblionumber,"recordDelete","biblioserver");
+}
+
+
+sub NEWnewitem {
+ my ( $dbh, $xmlhash, $biblionumber ) = @_;
+ #my $itemtype= MARCfind_itemtype($dbh,$biblionumber);
+my $itemtype=XML_readline_onerecord($xmlhash,"ctype","holdings");
+## In case we are re-importing marc records from bulk import do not change itemnumbers
+my $itemnumber=XML_readline_onerecord($xmlhash,"itemnumber","holdings");
+if ($itemnumber){
+NEWmoditem ( $dbh, $xmlhash, $biblionumber, $itemnumber);
+}else{
+
+##Add biblionumber to $record
+$xmlhash=XML_writeline($xmlhash,"biblionumber",$biblionumber,"holdings");
+ my $sth=$dbh->prepare("select notforloan from itemtypes where itemtype='$itemtype'");
+$sth->execute();
+my $notforloan=$sth->fetchrow;
+##Change the notforloan field if $notforloan found
+ if ($notforloan >0){
+ $xmlhash=XML_writeline($xmlhash,"notforloan",$notforloan,"holdings");
+ }
+my $dateaccessioned=XML_readline_onerecord($xmlhash,"dateaccessioned","holdings");
+unless($dateaccessioned){
+# find today's date
+my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
+localtime(time); $year +=1900; $mon +=1;
+my $date = "$year-".sprintf ("%0.2d", $mon)."-".sprintf("%0.2d",$mday);
+
+$xmlhash=XML_writeline($xmlhash,"dateaccessioned",$date,"holdings");
+}
+
+## Now calculate itempart of cutter-- This is NEU specific
+my $itemcallnumber=XML_readline_onerecord($xmlhash,"itemcallnumber","holdings");
+if ($itemcallnumber){
+my ($cutterextra)=itemcalculator($dbh,$biblionumber,$itemcallnumber);
+$xmlhash=XML_writeline($xmlhash,"cutterextra",$cutterextra,"holdings");
+}
+
+##NEU specific add cataloguers cardnumber as well
+my $me= C4::Context->userenv;
+my $cataloger=$me->{'cardnumber'} if ($me);
+$xmlhash=XML_writeline($xmlhash,"circid",$cataloger,"holdings") if $cataloger;
+
+##Add item to SQL
+my $itemnumber = &OLDnewitems( $dbh, $xmlhash );
+
+# add the item to zebra it will add the biblio as well!!!
+ ZEBRAop( $dbh, $biblionumber,"specialUpdate","biblioserver" );
+return $itemnumber;
+}## added new item
+
+}
+
+
+
+sub NEWmoditem{
+ my ( $dbh, $xmlhash, $biblionumber, $itemnumber ) = @_;
+
+##Add itemnumber incase lost (old bug 090c was lost sometimes) --just incase
+$xmlhash=XML_writeline($xmlhash,"itemnumber",$itemnumber,"holdings");
+##Add biblionumber incase lost on html
+$xmlhash=XML_writeline($xmlhash,"biblionumber",$biblionumber,"holdings");
+##Read barcode
+my $barcode=XML_readline_onerecord($xmlhash,"barcode","holdings");
+ my $ctype=XML_readline_onerecord($xmlhash,"ctype","holdings");
+ my $sth=$dbh->prepare("select notforloan from itemtypes where itemtype='$ctype'");
+$sth->execute();
+my $notforloan=$sth->fetchrow;
+##Change the notforloan field if $notforloan found
+ if ($notforloan >0){
+ $xmlhash=XML_writeline($xmlhash,"notforloan",$notforloan,"holdings");
+ }
+## Now calculate itempart of cutter-- This is NEU specific
+my $itemcallnumber=XML_readline_onerecord($xmlhash,"itemcallnumber","holdings");
+if ($itemcallnumber){
+my ($cutterextra)=itemcalculator($dbh,$biblionumber,$itemcallnumber);
+$xmlhash=XML_writeline($xmlhash,"cutterextra",$cutterextra,"holdings");
+}
+
+##NEU specific add cataloguers cardnumber as well
+my $me= C4::Context->userenv;
+my $cataloger=$me->{'cardnumber'} if ($me);
+$xmlhash=XML_writeline($xmlhash,"circid",$cataloger,"holdings") if $cataloger;
+my $xml=XML_hash2xml($xmlhash);
+ OLDmoditem( $dbh, $xml,$biblionumber,$itemnumber,$barcode,$ctype );
+ ZEBRAop($dbh,$biblionumber,"specialUpdate","biblioserver");
+}
+
+sub NEWdelitem {
+ my ( $dbh, $itemnumber ) = @_;
+my $sth=$dbh->prepare("SELECT biblionumber from items where itemnumber=?");
+$sth->execute($itemnumber);
+my $biblionumber=$sth->fetchrow;
+OLDdelitem( $dbh, $itemnumber ) ;
+ZEBRAop($dbh,$biblionumber,"specialUpdate","biblioserver");
+
+}
+
+
+
+
+sub NEWaddbiblio {
+ my ( $dbh, $xmlhash,$frameworkcode ) = @_;
+ my $sth = $dbh->prepare("Select max(biblionumber) from biblio");
+ $sth->execute;
+ my $data = $sth->fetchrow;
+ my $biblionumber = $data + 1;
+ $sth->finish;
+ # we must add biblionumber
+my $record;
+$xmlhash=XML_writeline($xmlhash,"biblionumber",$biblionumber,"biblios");
+
+###NEU specific add cataloguers cardnumber as well
+
+my $me= C4::Context->userenv;
+my $cataloger=$me->{'cardnumber'} if ($me);
+$xmlhash=XML_writeline($xmlhash,"indexedby",$cataloger,"biblios") if $cataloger;
+
+## We must add the indexing fields for LC in MARC record--TG
+&XMLmodLCindex($dbh,$xmlhash);
+
+##Find itemtype
+my $itemtype=XML_readline_onerecord($xmlhash,"itemtype","biblios");
+##Find ISBN
+my $isbn=XML_readline_onerecord($xmlhash,"isbn","biblios");
+##Find ISSN
+my $issn=XML_readline_onerecord($xmlhash,"issn","biblios");
+##Find Title
+my $title=XML_readline_onerecord($xmlhash,"title","biblios");
+##Find Author
+my $author=XML_readline_onerecord($xmlhash,"title","biblios");
+my $xml=XML_hash2xml($xmlhash);
+
+ $sth = $dbh->prepare("insert into biblio set biblionumber = ?,frameworkcode=?, itemtype=?,marcxml=?,title=?,author=?,isbn=?,issn=?" );
+ $sth->execute( $biblionumber,$frameworkcode, $itemtype,$xml ,$title,$author,$isbn,$issn );
+
+ $sth->finish;
+### Do not add biblio to ZEBRA unless there is an item with it -- depends on system preference defaults to NO
+if (C4::Context->preference('AddaloneBiblios')){
+ ZEBRAop($dbh,$biblionumber,"specialUpdate","biblioserver");
+}
+ return ($biblionumber);
+}
+
+sub NEWmodbiblio {
+ my ( $dbh, $biblionumber,$xmlhash,$frameworkcode ) = @_;
+##Add biblionumber incase lost on html
+
+$xmlhash=XML_writeline($xmlhash,"biblionumber",$biblionumber,"biblios");
+
+###NEU specific add cataloguers cardnumber as well
+my $me= C4::Context->userenv;
+my $cataloger=$me->{'cardnumber'} if ($me);
+
+$xmlhash=XML_writeline($xmlhash,"indexedby",$cataloger,"biblios") if $cataloger;
+
+## We must add the indexing fields for LC in MARC record--TG
+
+ XMLmodLCindex($dbh,$xmlhash);
+ OLDmodbiblio ($dbh,$xmlhash,$biblionumber,$frameworkcode);
+ my $ok=ZEBRAop($dbh,$biblionumber,"specialUpdate","biblioserver");
+ return ($biblionumber);
+}
+
+#
+#
+# OLD OLD OLD OLD OLD OLD OLD OLD OLD OLD OLD OLD OLD OLD OLD OLD OLD
+#
+#
+
+sub OLDnewitems {
+
+ my ( $dbh, $xmlhash) = @_;
+ my $sth = $dbh->prepare("SELECT max(itemnumber) from items");
+ my $data;
+ my $itemnumber;
+ $sth->execute;
+ $data = $sth->fetchrow_hashref;
+ $itemnumber = $data->{'max(itemnumber)'} + 1;
+ $sth->finish;
+ $xmlhash=XML_writeline( $xmlhash, "itemnumber", $itemnumber,"holdings" );
+my $biblionumber=XML_readline_onerecord($xmlhash,"biblionumber","holdings");
+ my $barcode=XML_readline_onerecord($xmlhash,"barcode","holdings");
+ my $ctype=XML_readline_onerecord($xmlhash,"ctype","holdings");
+my $xml=XML_hash2xml($xmlhash);
+ $sth = $dbh->prepare( "Insert into items set itemnumber = ?, biblionumber = ?,barcode = ?,marcxml=?, ctype=?" );
+ $sth->execute($itemnumber,$biblionumber,$barcode,$xml,$ctype);
+ return $itemnumber;
+}
+
+sub OLDmoditem {
+ my ( $dbh, $xml,$biblionumber,$itemnumber,$barcode,$ctype ) = @_;
+ my $sth =$dbh->prepare("replace items set biblionumber=?,marcxml=?,barcode=? , itemnumber=?, ctype=?");
+ $sth->execute($biblionumber,$xml,$barcode,$itemnumber, $ctype);
+ $sth->finish;
+}
+
+sub OLDdelitem {
+ my ( $dbh, $itemnumber ) = @_;
+my $sth = $dbh->prepare("select * from items where itemnumber=?");
+ $sth->execute($itemnumber);
+ if ( my $data = $sth->fetchrow_hashref ) {
+ $sth->finish;
+ my $query = "replace deleteditems set ";
+ my @bind = ();
+ foreach my $temp ( keys %$data ) {
+ $query .= "$temp = ?,";
+ push ( @bind, $data->{$temp} );
+ }
+
+ #replacing the last , by ",?)"
+ $query =~ s/\,$//;
+ $sth = $dbh->prepare($query);
+ $sth->execute(@bind);
+ $sth->finish;
+ $sth = $dbh->prepare("Delete from items where itemnumber=?");
+ $sth->execute($itemnumber);
+ $sth->finish;
+ }
+ $sth->finish;
+}
+
+sub OLDmodbiblio {
+# modifies the biblio table
+my ($dbh,$xmlhash,$biblionumber,$frameworkcode) = @_;
+ if (!$frameworkcode){
+ $frameworkcode="";
+ }
+##Find itemtype
+my $itemtype=XML_readline_onerecord($xmlhash,"itemtype","biblios");
+##Find ISBN
+my $isbn=XML_readline_onerecord($xmlhash,"isbn","biblios");
+##Find ISSN
+my $issn=XML_readline_onerecord($xmlhash,"issn","biblios");
+##Find Title
+my $title=XML_readline_onerecord($xmlhash,"title","biblios");
+##Find Author
+my $author=XML_readline_onerecord($xmlhash,"author","biblios");
+my $xml=XML_hash2xml($xmlhash);
+
+$isbn=~ s/(\.|\?|\;|\=|\-|\/|\\|\||\:|\*|\!|\,|\(|\)|\[|\]|\{|\}|\/)//g;
+$issn=~ s/(\.|\?|\;|\=|\-|\/|\\|\||\:|\*|\!|\,|\(|\)|\[|\]|\{|\}|\/)//g;
+$isbn=~s/^\s+|\s+$//g;
+$isbn=substr($isbn,0,13);
+ my $sth = $dbh->prepare("REPLACE biblio set biblionumber=?,marcxml=?,frameworkcode=? ,itemtype=? , title=?,author=?,isbn=?,issn=?" );
+ $sth->execute( $biblionumber ,$xml, $frameworkcode,$itemtype, $title,$author,$isbn,$issn);
+ $sth->finish;
+ return $biblionumber;
+}
+
+sub OLDdelbiblio {
+ my ( $dbh, $biblionumber ) = @_;
+ my $sth = $dbh->prepare("select * from biblio where biblionumber=?");
+ $sth->execute($biblionumber);
+ if ( my $data = $sth->fetchrow_hashref ) {
+ $sth->finish;
+ my $query = "replace deletedbiblio set ";
+ my @bind = ();
+ foreach my $temp ( keys %$data ) {
+ $query .= "$temp = ?,";
+ push ( @bind, $data->{$temp} );
+ }
+
+ #replacing the last , by ",?)"
+ $query =~ s/\,$//;
+ $sth = $dbh->prepare($query);
+ $sth->execute(@bind);
+ $sth->finish;
+ $sth = $dbh->prepare("Delete from biblio where biblionumber=?");
+ $sth->execute($biblionumber);
+ $sth->finish;
+ }
+ $sth->finish;
+}
+
+
+#
+#
+#
+#ZEBRA ZEBRA ZEBRA
+#
+#
+
+sub ZEBRAdelbiblio {
+## Zebra calls this routine to delete after it deletes biblio from ZEBRAddb
+ my ( $dbh, $biblionumber ) = @_;
+my $sth=$dbh->prepare("SELECT itemnumber FROM items where biblionumber=?");
+
+$sth->execute($biblionumber);
+ while (my $itemnumber =$sth->fetchrow){
+ OLDdelitem($dbh,$itemnumber) ;
+ }
+OLDdelbiblio($dbh,$biblionumber) ;
+}
+
+sub ZEBRAgetrecord{
+my $biblionumber=shift;
+my @kohafield="biblionumber";
+my @value=$biblionumber;
+my ($count, at result)=C4::Search::ZEBRAsearch_kohafields(\@kohafield,\@value);
+
+ if ($count>0){
+ my ( $xmlrecord, @itemsrecord) = XML_separate($result[0]);
+ return ($xmlrecord, @itemsrecord);
+ }else{
+ return (undef,undef);
+ }
+}
+
+sub ZEBRAop {
+### Puts the zebra update in queue writes in zebraserver table
+my ($dbh,$biblionumber,$op,$server)=@_;
+if (!$biblionumber){
+warn "Zebra received no biblionumber";
+}elsif (C4::Context->preference('onlineZEBRA')){
+my $marcxml;
+ if ($server eq "biblioserver"){
+ ($marcxml) =ZEBRA_readyXML($dbh,$biblionumber);
+ }elsif($server eq "authorityserver"){
+ $marcxml =C4::AuthoritiesMarc::XMLgetauthority($dbh,$biblionumber);
+ }
+ZEBRAopserver($marcxml,$op,$server,$biblionumber);
+ZEBRAopcommit($server);
+}else{
+my $sth=$dbh->prepare("insert into zebraqueue (biblio_auth_number ,server,operation) values(?,?,?)");
+$sth->execute($biblionumber,$server,$op);
+$sth->finish;
+
+}
+}
+
+sub ZEBRAopserver{
+
+###Accepts a $server variable thus we can use it to update biblios, authorities or other zebra dbs
+my ($record,$op,$server,$biblionumber)=@_;
+
+my @port;
+
+my $tried=0;
+my $recon=0;
+my $reconnect=0;
+$record=Encode::encode("UTF-8",$record);
+my $shadow=$server."shadow";
+reconnect:
+
+ my $Zconnbiblio=C4::Context->Zconnauth($server);
+if ($record){
+my $Zpackage = $Zconnbiblio->package();
+$Zpackage->option(action => $op);
+ $Zpackage->option(record => $record);
+ $Zpackage->option(recordIdOpaque => $biblionumber);
+retry:
+ $Zpackage->send("update");
+
+ my($error, $errmsg, $addinfo, $diagset) = $Zconnbiblio->error_x();
+ if ($error==10007 && $tried<3) {## timeout --another 30 looonng seconds for this update
+ sleep 1; ## wait a sec!
+ $tried=$tried+1;
+ goto "retry";
+ }elsif ($error==2 && $tried<2) {## timeout --temporary zebra error !whatever that means
+ sleep 2; ## wait two seconds!
+ $tried=$tried+1;
+ goto "retry";
+ }elsif($error==10004 && $recon==0){##Lost connection -reconnect
+ sleep 1; ## wait a sec!
+ $recon=1;
+ $Zpackage->destroy();
+ $Zconnbiblio->destroy();
+ goto "reconnect";
+ }elsif ($error){
+ # warn "Error-$server $op /errcode:, $error, /MSG:,$errmsg,$addinfo \n";
+ $Zpackage->destroy();
+ $Zconnbiblio->destroy();
+ return 0;
+ }
+
+$Zpackage->destroy();
+$Zconnbiblio->destroy();
+return 1;
+}
+return 0;
+}
+
+
+sub ZEBRAopcommit {
+my $server=shift;
+return unless C4::Context->config($server."shadow");
+my $Zconnbiblio=C4::Context->Zconnauth($server);
+
+my $Zpackage = $Zconnbiblio->package();
+ $Zpackage->send('commit');
+
+ my($error, $errmsg, $addinfo, $diagset) = $Zconnbiblio->error_x();
+ if ($error) { ## This is serious ZEBRA server is not updating
+ $Zpackage->destroy();
+ $Zconnbiblio->destroy();
+ return 0;
+ }
+$Zpackage->destroy();
+$Zconnbiblio->destroy();
+return 1;
+}
+sub ZEBRA_readyXML{
+my ($dbh,$biblionumber)=@_;
+my $biblioxml=XMLgetbiblio($dbh,$biblionumber);
+my @itemxml=XMLgetallitems($dbh,$biblionumber);
+my $zebraxml=collection_header();
+$zebraxml.="<koharecord>";
+$zebraxml.=$biblioxml;
+$zebraxml.="<holdings>";
+ foreach my $item(@itemxml){
+ $zebraxml.=$item if $item;
+ }
+$zebraxml.="</holdings>";
+$zebraxml.="</koharecord>";
+$zebraxml.="</kohacollection>";
+return $zebraxml;
+}
+
+sub ZEBRA_readyXML_noheader{
+my ($dbh,$biblionumber)=@_;
+my $biblioxml=XMLgetbiblio($dbh,$biblionumber);
+my @itemxml=XMLgetallitems($dbh,$biblionumber);
+my $zebraxml="<koharecord>";
+$zebraxml.=$biblioxml;
+$zebraxml.="<holdings>";
+ foreach my $item(@itemxml){
+ $zebraxml.=$item if $item;
+ }
+$zebraxml.="</holdings>";
+$zebraxml.="</koharecord>";
+return $zebraxml;
+}
+
+#
+#
+# various utility subs and those not complying to new rules
+#
+#
+
+sub newbiblio {
+## Used in acqui management -- creates the biblio from koha hash
+ my ($biblio) = @_;
+ my $dbh = C4::Context->dbh;
+my $record=XMLkoha2marc($dbh,$biblio,"biblios");
+ my $biblionumber=NEWnewbiblio($dbh,$record);
+ return ($biblionumber);
+}
+sub modbiblio {
+## Used in acqui management -- modifies the biblio from koha hash rather than xml-hash
+ my ($biblio) = @_;
+ my $dbh = C4::Context->dbh;
+my $record=XMLkoha2marc($dbh,$biblio,"biblios");
+ my $biblionumber=NEWmodbiblio($dbh,$record,$biblio->{biblionumber});
+ return ($biblionumber);
+}
+
+sub newitems {
+## Used in acqui management -- creates the item from hash rather than marc-record
+ my ( $item, @barcodes ) = @_;
+ my $dbh = C4::Context->dbh;
+ my $errors;
+ my $itemnumber;
+ my $error;
+ foreach my $barcode (@barcodes) {
+ $item->{barcode}=$barcode;
+my $record=MARCkoha2marc($dbh,$item,"holdings");
+ my $itemnumber= NEWnewitem($dbh,$record,$item->{biblionumber});
+
+ }
+ return $itemnumber ;
+}
+
+
+
+
+sub getitemtypes {
+ my $dbh = C4::Context->dbh;
+ my $query = "select * from itemtypes order by description";
+ my $sth = $dbh->prepare($query);
+
+ # || die "Cannot prepare $query" . $dbh->errstr;
+ my $count = 0;
+ my @results;
+ $sth->execute;
+ # || die "Cannot execute $query\n" . $sth->errstr;
+ while ( my $data = $sth->fetchrow_hashref ) {
+ $results[$count] = $data;
+ $count++;
+ } # while
+
+ $sth->finish;
+ return ( $count, @results );
+} # sub getitemtypes
+
+
+
+sub getkohafields{
+#returns MySQL like fieldnames to emulate searches on sql like fieldnames
+my $type=shift;
+## Either opac or intranet to select appropriate fields
+## Assumes intranet
+$type="intra" unless $type;
+if ($type eq "intranet"){ $type="intra";}
+my $dbh = C4::Context->dbh;
+ my $i=0;
+my @results;
+$type=$type."show";
+my $sth=$dbh->prepare("SELECT * FROM koha_attr where $type=1 order by label");
+$sth->execute();
+while (my $data=$sth->fetchrow_hashref){
+ $results[$i]=$data;
+ $i++;
+ }
+$sth->finish;
+return ($i, at results);
+}
+
+
+
+
+
+sub DisplayISBN {
+## Old style ISBN handling should be modified to accept 13 digits
+
+ my ($isbn)=@_;
+ my $seg1;
+ if(substr($isbn, 0, 1) <=7) {
+ $seg1 = substr($isbn, 0, 1);
+ } elsif(substr($isbn, 0, 2) <= 94) {
+ $seg1 = substr($isbn, 0, 2);
+ } elsif(substr($isbn, 0, 3) <= 995) {
+ $seg1 = substr($isbn, 0, 3);
+ } elsif(substr($isbn, 0, 4) <= 9989) {
+ $seg1 = substr($isbn, 0, 4);
+ } else {
+ $seg1 = substr($isbn, 0, 5);
+ }
+ my $x = substr($isbn, length($seg1));
+ my $seg2;
+ if(substr($x, 0, 2) <= 19) {
+# if(sTmp2 < 10) sTmp2 = "0" sTmp2;
+ $seg2 = substr($x, 0, 2);
+ } elsif(substr($x, 0, 3) <= 699) {
+ $seg2 = substr($x, 0, 3);
+ } elsif(substr($x, 0, 4) <= 8399) {
+ $seg2 = substr($x, 0, 4);
+ } elsif(substr($x, 0, 5) <= 89999) {
+ $seg2 = substr($x, 0, 5);
+ } elsif(substr($x, 0, 6) <= 9499999) {
+ $seg2 = substr($x, 0, 6);
+ } else {
+ $seg2 = substr($x, 0, 7);
+ }
+ my $seg3=substr($x,length($seg2));
+ $seg3=substr($seg3,0,length($seg3)-1) ;
+ my $seg4 = substr($x, -1, 1);
+ return "$seg1-$seg2-$seg3-$seg4";
+}
+sub calculatelc{
+## Function to create padded LC call number for sorting items with their LC code. Not exported
+my ($classification)=@_;
+$classification=~s/^\s+|\s+$//g;
+my $i=0;
+my $lc2;
+my $lc1;
+for ($i=0; $i<length($classification);$i++){
+my $c=(substr($classification,$i,1));
+ if ($c ge '0' && $c le '9'){
+
+ $lc2=substr($classification,$i);
+ last;
+ }else{
+ $lc1.=substr($classification,$i,1);
+
+ }
+}#while
+
+my $other=length($lc1);
+if(!$lc1){$other=0;}
+my $extras;
+if ($other<4){
+ for (1..(4-$other)){
+ $extras.="0";
+ }
+}
+ $lc1.=$extras;
+$lc2=~ s/^ //g;
+
+$lc2=~ s/ //g;
+$extras="";
+##Find the decimal part of $lc2
+my $pos=index($lc2,".");
+if ($pos<0){$pos=length($lc2);}
+if ($pos>=0 && $pos<5){
+##Pad lc2 with zeros to create a 5digit decimal needed in marc record to sort as numeric
+
+ for (1..(5-$pos)){
+ $extras.="0";
+ }
+}
+$lc2=$extras.$lc2;
+return($lc1.$lc2);
+}
+
+sub itemcalculator{
+## Sublimentary function to obtain sorted LC for items. Not exported
+my ($dbh,$biblionumber,$callnumber)=@_;
+my $xmlhash=XMLgetbibliohash($dbh,$biblionumber);
+my $lc=XML_readline_onerecord($xmlhash,"classification","biblios");
+my $cutter=XML_readline_onerecord($xmlhash,"subclass","biblios");
+my $all=$lc." ".$cutter;
+my $total=length($all);
+my $cutterextra=substr($callnumber,$total);
+return $cutterextra;
+
+}
+
+
+#### This function allows decoding of only title and author out of a MARC record
+ sub func_title_author {
+ my ($tagno,$tagdata) = @_;
+my ($titlef,$subf,$authf);
+ ($titlef,$subf)=&MARCfind_marc_from_kohafield("title","biblios");
+ ($authf,$subf)=&MARCfind_marc_from_kohafield("author","biblios");
+ return ($tagno == $titlef || $tagno == $authf);
+ }
+
+
+
+
+1;
+__END__
+=back
+
+=head1 AUTHOR
+
+Koha Developement team <info at koha.org>
+
+
+
Index: Biblioadd.pm
===================================================================
RCS file: Biblioadd.pm
diff -N Biblioadd.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Biblioadd.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,521 @@
+package C4::Biblioadd;
+# New PackageI added by tgarip at neu.edu.tr 25/02/07
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+use strict;
+require Exporter;
+use C4::Context;
+use XML::Simple;
+use Encode;
+use MARC::Record;
+use MARC::File::USMARC;
+use C4::Biblio;
+use Data::Dumper;
+use vars qw( $tagslib);
+use vars qw( $authorised_values_sth);
+
+my $format="USMARC";
+$format="UNIMARC" if (C4::Context->preference('marcflavour') eq 'UNIMARC');
+use MARC::File::XML(RecordFormat =>$format);
+
+use vars qw($VERSION @ISA @EXPORT);
+
+# set the version for version checking
+$VERSION = 4.01;
+
+ at ISA = qw(Exporter);
+
+
+ at EXPORT = qw(
+&MARCfindbreeding
+&ImportDVD
+&build_authorized_values_list
+&create_input
+&build_tabs
+&build_hidden_data
+);
+
+=item MARCfindbreeding
+
+ $record = MARCfindbreeding($dbh, $breedingid,$frameworkcode);
+
+Look up the breeding farm with database handle $dbh, for the
+record with id $breedingid. If found, returns the decoded
+MARC::Record; otherwise, -1 is returned (FIXME).
+Returns as second parameter the character encoding.
+
+=cut
+
+sub MARCfindbreeding {
+ my ($dbh,$id,$oldbiblionumber) = @_;
+ my $sth = $dbh->prepare("select marc,encoding from marc_breeding where id=?");
+ $sth->execute($id);
+ my ($marc,$encoding) = $sth->fetchrow;
+ $sth->finish;
+ if ($marc) {
+ my $record = MARC::File::USMARC::decode($marc);
+ if (ref($record) eq undef) {
+ return -1;
+ }
+ if (C4::Context->preference("z3950NormalizeAuthor") and C4::Context->preference("z3950AuthorAuthFields")){
+ my ($tag,$subfield) = MARCfind_marc_from_kohafield("author","biblios");
+ my $auth_fields = C4::Context->preference("z3950AuthorAuthFields");
+ my @auth_fields= split /,/,$auth_fields;
+ my $field;
+ if ($record->field($tag)){
+ foreach my $tmpfield ($record->field($tag)->subfields){
+ my $subfieldcode=shift @$tmpfield;
+ my $subfieldvalue=shift @$tmpfield;
+ if ($field){
+ $field->add_subfields("$subfieldcode"=>$subfieldvalue) if ($subfieldcode ne $subfield);
+ } else {
+ $field=MARC::Field->new($tag,"","",$subfieldcode=>$subfieldvalue) if ($subfieldcode ne $subfield);
+ }
+ }
+ }
+ $record->delete_field($record->field($tag));
+ foreach my $fieldtag (@auth_fields){
+ next unless ($record->field($fieldtag));
+ my $lastname = $record->field($fieldtag)->subfield('a');
+ my $firstname= $record->field($fieldtag)->subfield('b');
+ my $title = $record->field($fieldtag)->subfield('c');
+ my $number= $record->field($fieldtag)->subfield('d');
+ if ($title){
+ $field->add_subfields("$subfield"=>ucfirst($title)." ".ucfirst($firstname)." ".$number);
+ }else{
+ $field->add_subfields("$subfield"=>ucfirst($firstname).", ".ucfirst($lastname));
+ }
+ }
+ $record->insert_fields_ordered($field);
+ }
+##Delete biblionumber tag in case a similar tag is used in imported MARC ##
+ my ( $tagfield, $tagsubfield ) =MARCfind_marc_from_kohafield("biblionumber","biblios");
+ my $old_field = $record->field($tagfield);
+ $record->delete_field($old_field);
+ ##add the old biblionumber if a modif but coming from breedingfarm
+ if ($oldbiblionumber){
+ my $newfield;
+ if ($tagfield<10){
+ $newfield = MARC::Field->new($tagfield, $oldbiblionumber);
+ }else{
+ $newfield = MARC::Field->new($tagfield, '', '', "$tagsubfield" => $oldbiblionumber);
+ }
+ $record->insert_fields_ordered($newfield);
+ }
+ my $xml=MARC::File::XML::record($record);
+
+ my $xmlhash=XML_xml2hash_onerecord($xml);
+ return $xmlhash,$encoding;
+
+ }
+ return -1;
+}
+
+=item ImportDVD
+
+=cut
+
+sub ImportDVD {
+my ($filename,$oldbiblionumber)=@_;
+
+## Fixme the path to be variable
+my $fullname=C4::Context->config('intranetdir')."/htdocs/uploaded-files/tmp-pdf/".$filename;
+
+my $xml;
+my $xmlhash;
+open(IN,"<" ,$fullname) or die $!;
+while (<IN>){
+$xml.=$_;
+}
+close(IN);
+$xml=Encode::encode('utf8',$xml);
+$xmlhash=XML_xml2hash_onerecord($xml);
+if ($oldbiblionumber){
+$xmlhash=XML_writeline($xmlhash,"biblionumber",$oldbiblionumber,"biblios");
+}
+return $xmlhash;
+}
+=item build_authorized_values_list
+
+=cut
+
+sub build_authorized_values_list {
+ my($tag, $subfield, $value, $dbh,$authorised_values_sth,$tagslib) = @_;
+
+ my @authorised_values;
+ my %authorised_lib;
+ my ($itemtype,$description);
+ # builds list, depending on authorised value...
+
+ #---- branch
+ if ($tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "branches" ) {
+ my $sth=$dbh->prepare("select branchcode,branchname from branches order by branchname");
+ $sth->execute;
+ push @authorised_values, ""
+ unless ($tagslib->{$tag}->{$subfield}->{mandatory});
+
+ while (my ($branchcode,$branchname) = $sth->fetchrow_array) {
+ push @authorised_values, $branchcode;
+ $authorised_lib{$branchcode}=$branchname;
+ }
+
+ #----- itemtypes
+ } elsif ($tagslib->{$tag}->{$subfield}->{authorised_value} eq "itemtypes") {
+ my $sth=$dbh->prepare("select itemtype,description from itemtypes order by description");
+ $sth->execute;
+ push @authorised_values, "" unless ($tagslib->{$tag}->{$subfield}->{mandatory});
+
+ while ( ($itemtype,$description) = $sth->fetchrow_array) {
+ push @authorised_values, $itemtype;
+ $authorised_lib{$itemtype}=$description;
+ }
+ $value=$itemtype unless ($value);
+
+ #---- "true" authorised value
+ } else {
+ $authorised_values_sth->execute($tagslib->{$tag}->{$subfield}->{authorised_value});
+
+ push @authorised_values, "" unless ($tagslib->{$tag}->{$subfield}->{mandatory});
+
+ while (my ($value,$lib) = $authorised_values_sth->fetchrow_array) {
+ push @authorised_values, $value;
+ $authorised_lib{$value}=$lib;
+ }
+ }
+ return CGI::scrolling_list( -name => 'field_value',
+ -values => \@authorised_values,
+ -default => $value,
+ -labels => \%authorised_lib,
+ -override => 1,
+ -size => 1,
+ -multiple => 0 );
+}
+
+=item create_input
+ builds the <input ...> entry for a subfield.
+=cut
+sub create_input {
+ my ($tag,$subfield,$value,$i,$tabloop,$rec,$authorised_values_sth,$id,$tagslib) = @_;
+ my $dbh=C4::Context->dbh;
+ $value =~ s/"/"/g;
+ my %subfield_data;
+ $subfield_data{id}=$id;
+ $subfield_data{tag}=$tag;
+ $subfield_data{subfield}=$subfield;
+ $subfield_data{marc_lib}="<span id=\"error$i\">".$tagslib->{$tag}->{$subfield}->{lib}."</span>";
+ $subfield_data{marc_lib_plain}=$tagslib->{$tag}->{$subfield}->{lib};
+ $subfield_data{tag_mandatory}=$tagslib->{$tag}->{mandatory};
+ $subfield_data{mandatory}=$tagslib->{$tag}->{$subfield}->{mandatory};
+ $subfield_data{repeatable}=$tagslib->{$tag}->{$subfield}->{repeatable};
+ $subfield_data{index} = $i;
+ $subfield_data{visibility} = "display:none" if (substr($tagslib->{$tag}->{$subfield}->{hidden},2,1) gt "0") ; #check parity
+ if ($tagslib->{$tag}->{$subfield}->{authorised_value}) {
+ $subfield_data{marc_value}= build_authorized_values_list($tag, $subfield, $value, $dbh,$authorised_values_sth,$tagslib);
+ # it's an authority field
+ } elsif ($tagslib->{$tag}->{$subfield}->{authtypecode}) {
+
+ $subfield_data{marc_value}="<input onblur=\"this.style.backgroundColor='#ffffff';\" onfocus=\"this.style.backgroundColor='#ffffff;'\"\" tabindex=\"1\" type=\"text\" name=\"field_value\" id=\"field_value$id\" value=\"$value\" size=\"40\" maxlength=\"255\" DISABLE READONLY> <a style=\"cursor: help;\" href=\"javascript:Dopop('../authorities/auth_finder.pl?authtypecode=".$tagslib->{$tag}->{$subfield}->{authtypecode}."&index=$id',$id);\">...</a>";
+ # it's a plugin field
+ } elsif ($tagslib->{$tag}->{$subfield}->{'value_builder'}) {
+ # opening plugin. Just check wether we are on a developper computer on a production one
+ # (the cgidir differs)
+ my $cgidir = C4::Context->intranetdir ."/cgi-bin/value_builder";
+ unless (opendir(DIR, "$cgidir")) {
+ $cgidir = C4::Context->intranetdir."/value_builder";
+ }
+ my $plugin=$cgidir."/".$tagslib->{$tag}->{$subfield}->{'value_builder'};
+ do $plugin;
+ my $extended_param = plugin_parameters($dbh,$rec,$tagslib,$i,$tabloop);
+ my ($function_name,$javascript) = plugin_javascript($dbh,$rec,$tagslib,$i,$tabloop);
+ $subfield_data{marc_value}="<input tabindex=\"1\" type=\"text\" name=\"field_value\" id=\"field_value$id\" value=\"$value\" size=\"40\" maxlength=\"255\" DISABLE READONLY OnFocus=\"javascript:Focus$function_name($i)\" OnBlur=\"javascript:Blur$function_name($i); \"> <a style=\"cursor: help;\" href=\"javascript:Clic$function_name($i)\">...</a> $javascript";
+ # it's an hidden field
+ } elsif ($tag eq '') {
+ $subfield_data{marc_value}="<input onblur=\"this.style.backgroundColor='#ffffff';\" onfocus=\"this.style.backgroundColor='#ffffff'; \" tabindex=\"1\" type=\"hidden\" name=\"field_value\" id=\"field_value$id\" value=\"$value\">";
+ } elsif (substr($tagslib->{$tag}->{$subfield}->{'hidden'},2,1) gt "1") {
+
+ $subfield_data{marc_value}="<input onblur=\"this.style.backgroundColor='#ffffff';\" onfocus=\"this.style.backgroundColor='#ffffff'; \" tabindex=\"1\" type=\"text\" name=\"field_value\" id=\"field_value$id\" value=\"$value\" size=\"40\" maxlength=\"255\" >";
+ # it's a standard field
+ } else {
+ if (length($value) >100) {
+ $subfield_data{marc_value}="<textarea tabindex=\"1\" name=\"field_value\" id=\"field_value$id\" cols=\"40\" rows=\"5\" >$value</textarea>";
+ } else {
+ $subfield_data{marc_value}="<input onblur=\"this.style.backgroundColor='#ffffff';\" onfocus=\"this.style.backgroundColor='#ffffff'; \" tabindex=\"1\" type=\"text\" name=\"field_value\" id=\"field_value$id\" value=\"$value\" size=\"50\">"; #"
+ }
+ }
+ return \%subfield_data;
+}
+
+sub build_tabs {
+ my($template, $xmlhash, $dbh,$addedfield,$tagslib,$authorised_values_sth) = @_;
+ # fill arrays
+ my @loop_data =();
+ my $tag;
+ my $i=0;
+my $id=100;
+
+my ($biblionumtagfield,$biblionumtagsubfield) = &MARCfind_marc_from_kohafield($dbh,"biblionumber","biblios");
+
+my $biblio;
+my $controlfields;
+my $leader;
+if ($xmlhash){
+ $biblio=$xmlhash->{'datafield'};
+ $controlfields=$xmlhash->{'controlfield'};
+ $leader=$xmlhash->{'leader'};
+}
+
+ my @BIG_LOOP;
+my %built;
+
+# loop through each tab 0 through 9
+for (my $tabloop = 0; $tabloop <= 9; $tabloop++) {
+
+ my @loop_data = ();
+ foreach my $tag (sort(keys (%{$tagslib}))) {
+ next if ($tag eq $biblionumtagfield);## Otherwise biblionumber will be duplicated on modifs if user has set visibility to true
+ my $indicator;
+ # if MARC::Record is not empty => use it as master loop, then add missing subfields that should be in the tab.
+ # if MARC::Record is empty => use tab as master loop.
+ my @subfields_data;
+
+ if ($xmlhash) {
+ ####
+ my %tagdefined;
+ my %definedsubfields;
+
+ my ($ind1,$ind2);
+
+ if ($tag>9){
+ foreach my $data (@$biblio){
+ my @subfields_data;
+ undef %definedsubfields;
+ if ($data->{'tag'} eq $tag){
+ $tagdefined{$tag}=1 ;
+ $ind1=" ";
+ $ind2=" ";
+ foreach my $subfieldcode ( $data->{'subfield'}){
+ foreach my $code ( @$subfieldcode){
+ next if ($tagslib->{$tag}->{$code->{'code'}}->{tab} ne $tabloop);
+ my $subfield=$code->{'code'} ;
+ my $value=$code->{'content'};
+ $definedsubfields{$tag.$subfield}=1 ;
+ $built{$tag}=1;
+ push(@subfields_data, &create_input($tag,$subfield,$value,$i,$tabloop,$xmlhash,$authorised_values_sth,$id,$tagslib)) ;
+ $i++ ;
+ }
+ } ##each subfield
+ $ind1=$data->{'ind1'};
+ $ind2= $data->{'ind2'};
+
+
+ # now, loop again to add parameter subfield that are not in the MARC::Record
+
+ foreach my $subfield (sort( keys %{$tagslib->{$tag}})) {
+ next if (length $subfield !=1);
+ next if ($tagslib->{$tag}->{$subfield}->{tab} ne $tabloop);
+ next if ((substr($tagslib->{$tag}->{$subfield}->{hidden},2,1) gt "1") ); #check for visibility flag
+ next if ($definedsubfields{$tag.$subfield} );
+ push(@subfields_data, &create_input($tag,$subfield,'',$i,$tabloop,$xmlhash,$authorised_values_sth,$id,$tagslib));
+ $definedsubfields{$tag.$subfield}=1;
+ $i++;
+ }
+ if ($#subfields_data >= 0) {
+ my %tag_data;
+ $tag_data{tag} = $tag;
+ $tag_data{tag_lib} = $tagslib->{$tag}->{lib};
+ $tag_data{repeatable} = $tagslib->{$tag}->{repeatable};
+ $tag_data{indicator} = $ind1.$ind2 if ($tag>=10);
+ $tag_data{subfield_loop} = \@subfields_data;
+ push (@loop_data, \%tag_data);
+
+ }
+ $id++;
+ }## if tag matches
+
+ }#eachdata
+ }else{ ## tag <10
+ if ($tag eq "000" || $tag eq "LDR"){
+ my $subfield="@";
+ next if ($tagslib->{$tag}->{$subfield}->{tab} ne $tabloop);
+ my @subfields_data;
+ my $value=$leader->[0] if $leader->[0];
+ $tagdefined{$tag}=1 ;
+ push(@subfields_data, &create_input($tag,$subfield,$value,$i,$tabloop,$xmlhash,$authorised_values_sth,$id,$tagslib));
+ $i++;
+ if ($#subfields_data >= 0) {
+ my %tag_data;
+ $tag_data{tag} = $tag;
+ $tag_data{tag_lib} = $tagslib->{$tag}->{lib};
+ $tag_data{repeatable} = $tagslib->{$tag}->{repeatable};
+ $tag_data{subfield_loop} = \@subfields_data;
+ $tag_data{fixedfield} = 1;
+ push (@loop_data, \%tag_data);
+ }
+ }else{
+ foreach my $control (@$controlfields){
+ my $subfield="@";
+ next if ($tagslib->{$tag}->{$subfield}->{tab} ne $tabloop);
+ my @subfields_data;
+ if ($control->{'tag'} eq $tag){
+ $tagdefined{$tag}=1 ;
+ my $value=$control->{'content'} ;
+ $definedsubfields{$tag.'@'}=1;
+ push(@subfields_data, &create_input($tag,$subfield,$value,$i,$tabloop,$xmlhash,$authorised_values_sth,$id,$tagslib));
+ $i++;
+
+ $built{$tag}=1;
+
+ if ($#subfields_data >= 0) {
+ my %tag_data;
+ $tag_data{tag} = $tag;
+ $tag_data{tag_lib} = $tagslib->{$tag}->{lib};
+ $tag_data{repeatable} = $tagslib->{$tag}->{repeatable};
+ $tag_data{subfield_loop} = \@subfields_data;
+ $tag_data{fixedfield} = 1;
+ push (@loop_data, \%tag_data);
+ }
+ $id++;
+ }## tag matches
+ }# each control
+ }
+ }##tag >9
+
+
+ ##### Any remaining tag
+ my @subfields_data;
+ # now, loop again to add parameter subfield that are not in the MARC::Record
+ foreach my $subfield (sort( keys %{$tagslib->{$tag}})) {
+ next if ($tagdefined{$tag} );
+ next if (length $subfield !=1);
+ next if ($tagslib->{$tag}->{$subfield}->{tab} ne $tabloop);
+ next if ((substr($tagslib->{$tag}->{$subfield}->{hidden},2,1) gt "1") ); #check for visibility flag
+
+ push(@subfields_data, &create_input($tag,$subfield,'',$i,$tabloop,$xmlhash,$authorised_values_sth,$id,$tagslib));
+ $tagdefined{$tag.$subfield}=1;
+ $i++;
+ }
+ if ($#subfields_data >= 0) {
+ my %tag_data;
+ $tag_data{tag} = $tag;
+ $tag_data{tag_lib} = $tagslib->{$tag}->{lib};
+ $tag_data{repeatable} = $tagslib->{$tag}->{repeatable};
+ $tag_data{indicator} = $ind1.$ind2 if ($tag>=10);
+ $tag_data{subfield_loop} = \@subfields_data;
+ if ($tag<10) {
+ $tag_data{fixedfield} = 1;
+ }
+
+ push (@loop_data, \%tag_data);
+ }
+
+
+ if ($addedfield eq $tag) {
+ my %tag_data;
+ my @subfields_data;
+ $id++;
+ $tagdefined{$tag}=1 ;
+ foreach my $subfield (sort( keys %{$tagslib->{$tag}})) {
+ next if (length $subfield !=1);
+ next if ($tagslib->{$tag}->{$subfield}->{tab} ne $tabloop);
+ next if ((substr($tagslib->{$tag}->{$subfield}->{hidden},2,1) gt "1") ); #check for visibility flag
+ $addedfield="";
+ push(@subfields_data, &create_input($tag,$subfield,'',$i,$tabloop,$xmlhash,$authorised_values_sth,$id,$tagslib));
+ $i++;
+ }
+ if ($#subfields_data >= 0) {
+ $tag_data{tag} = $tag;
+ $tag_data{tag_lib} = $tagslib->{$tag}->{lib};
+ $tag_data{repeatable} = $tagslib->{$tag}->{repeatable};
+ $tag_data{indicator} = ' ' if ($tag>=10);
+ $tag_data{subfield_loop} = \@subfields_data;
+ if ($tag<10) {
+ $tag_data{fixedfield} = 1;
+ }
+ push (@loop_data, \%tag_data);
+
+ }
+
+ }
+
+ # if breeding is empty
+ } else {
+ my @subfields_data;
+ foreach my $subfield (sort(keys %{$tagslib->{$tag}})) {
+ next if (length $subfield !=1);
+ next if ((substr($tagslib->{$tag}->{$subfield}->{hidden},2,1) gt "1") ); #check for visibility flag
+ next if ($tagslib->{$tag}->{$subfield}->{tab} ne $tabloop);
+ push(@subfields_data, &create_input($tag,$subfield,'',$i,$tabloop,$xmlhash,$authorised_values_sth,$id,$tagslib));
+ $i++;
+ }
+ if ($#subfields_data >= 0) {
+ my %tag_data;
+ $tag_data{tag} = $tag;
+ $tag_data{tag_lib} = $tagslib->{$tag}->{lib};
+ $tag_data{repeatable} = $tagslib->{$tag}->{repeatable};
+ $tag_data{indicator} = $indicator;
+ $tag_data{subfield_loop} = \@subfields_data;
+ $tag_data{tagfirstsubfield} = $tag_data{subfield_loop}[0];
+ if ($tag<10) {
+ $tag_data{fixedfield} = 1;
+ }
+ push (@loop_data, \%tag_data);
+
+ }
+ }
+ $id++;
+ }
+ if ($#loop_data >=0) {
+ my %big_loop_line;
+ $big_loop_line{number}=$tabloop;
+ $big_loop_line{innerloop}=\@loop_data;
+ push @BIG_LOOP,\%big_loop_line;
+ }
+
+ $template->param(BIG_LOOP => \@BIG_LOOP);
+#return \@BIG_LOOP;
+}## tab loop
+
+}
+
+
+sub build_hidden_data {
+ # build hidden data =>
+ # we store everything, even if we show only requested subfields.
+my $tagslib=shift;
+ my @loop_data =();
+ my $i=0;
+ foreach my $tag (keys %{$tagslib}) {
+ my $previous_tag = '';
+
+ # loop through each subfield
+ foreach my $subfield (keys %{$tagslib->{$tag}}) {
+ next if ($subfield eq 'lib');
+ next if ($subfield eq 'tab');
+ next if ($subfield eq 'mandatory');
+ next if ($subfield eq 'repeatable');
+ next if ($tagslib->{$tag}->{$subfield}->{'tab'} ne "-1");
+ my %subfield_data;
+ $subfield_data{marc_lib}=$tagslib->{$tag}->{$subfield}->{lib};
+ $subfield_data{marc_mandatory}=$tagslib->{$tag}->{$subfield}->{mandatory};
+ $subfield_data{marc_repeatable}=$tagslib->{$tag}->{$subfield}->{repeatable};
+ $subfield_data{marc_value}="<input type=\"hidden\" name=\"field_value[]\">";
+ push(@loop_data, \%subfield_data);
+ $i++
+ }
+return $tagslib;
+ }
+}
Index: BookShelves.pm
===================================================================
RCS file: BookShelves.pm
diff -N BookShelves.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ BookShelves.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,681 @@
+# -*- tab-width: 8 -*-
+# Please use 8-character tabs for this file (indents are every 4 characters)
+
+package C4::BookShelves;
+
+# $Id: BookShelves.pm,v 1.1.2.1 2007/03/10 01:35:34 tgarip1957 Exp $
+
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+require Exporter;
+use C4::Context;
+use C4::Circulation::Circ2;
+use C4::AcademicInfo;
+use C4::Search;
+use C4::Date;
+use C4::Biblio;
+use vars qw($VERSION @ISA @EXPORT);
+
+# set the version for version checking
+$VERSION = 0.01;
+
+=head1 NAME
+
+C4::BookShelves - Functions for manipulating Koha virtual bookshelves
+
+=head1 SYNOPSIS
+
+ use C4::BookShelves;
+
+=head1 DESCRIPTION
+
+This module provides functions for manipulating virtual bookshelves,
+including creating and deleting bookshelves, and adding and removing
+items to and from bookshelves.
+
+=head1 FUNCTIONS
+
+=over 2
+
+=cut
+
+ at ISA = qw(Exporter);
+ at EXPORT = qw(&GetShelfList &GetShelfContents &AddToShelf &AddToShelfFromBiblio
+ &RemoveFromShelf &AddShelf &RemoveShelf
+ &ShelfPossibleAction
+
+ &GetShelfListExt &AddShelfExt &EditShelfExt &RemoveShelfExt
+ &GetShelfInfo &GetShelfContentsExt &RemoveFromShelfExt
+ &GetShelfListOfExt &AddToShelfExt
+
+ &AddRequestToShelf &CountShelfRequest &GetShelfRequests
+ &RejectShelfRequest &CatalogueShelfRequest &GetShelfRequestOwner
+ &GetShelfRequest);
+
+
+my $dbh;
+ $dbh = C4::Context->dbh;
+
+=item ShelfPossibleAction
+
+=over 4
+
+=item C<$loggedinuser,$shelfnumber,$action>
+
+$action can be "view" or "manage".
+
+Returns 1 if the user can do the $action in the $shelfnumber shelf.
+Returns 0 otherwise.
+
+=back
+
+=cut
+sub ShelfPossibleAction {
+ my ($loggedinuser,$shelfnumber,$action)= @_;
+ my $sth = $dbh->prepare("select owner,category from bookshelf where shelfnumber=?");
+ $sth->execute($shelfnumber);
+ my ($owner,$category) = $sth->fetchrow;
+ return 1 if (($category>=3 or $owner eq $loggedinuser) && $action eq 'manage');
+ return 1 if (($category>= 2 or $owner eq $loggedinuser) && $action eq 'view');
+ return 0;
+}
+
+=item GetShelfList
+
+ $shelflist = &GetShelfList();
+ ($shelfnumber, $shelfhash) = each %{$shelflist};
+
+Looks up the virtual bookshelves, and returns a summary. C<$shelflist>
+is a reference-to-hash. The keys are the bookshelf numbers
+(C<$shelfnumber>, above), and the values (C<$shelfhash>, above) are
+themselves references-to-hash, with the following keys:
+
+=over 4
+
+=item C<$shelfhash-E<gt>{shelfname}>
+
+A string. The name of the shelf.
+
+=item C<$shelfhash-E<gt>{count}>
+
+The number of books on that bookshelf.
+
+=back
+
+=cut
+#'
+# FIXME - Wouldn't it be more intuitive to return a list, rather than
+# a reference-to-hash? The shelf number can be just another key in the
+# hash.
+sub GetShelfList {
+ my ($owner,$mincategory) = @_;
+ # mincategory : 2 if the list is for "look". 3 if the list is for "Select bookshelf for adding a book".
+ # bookshelves of the owner are always selected, whatever the category
+ my $sth=$dbh->prepare("SELECT bookshelf.shelfnumber, bookshelf.shelfname,owner,surname,firstname, category,
+ count(shelfcontents.itemnumber) as count
+ FROM bookshelf
+ LEFT JOIN shelfcontents
+ ON bookshelf.shelfnumber = shelfcontents.shelfnumber
+ left join borrowers on bookshelf.owner = borrowers.borrowernumber
+
+ where owner=? or category>=?
+ GROUP BY bookshelf.shelfnumber order by shelfname");
+ $sth->execute($owner,$mincategory);
+ my %shelflist;
+ while (my ($shelfnumber, $shelfname,$owner,$surname,$firstname,$category,$count) = $sth->fetchrow) {
+ $shelflist{$shelfnumber}->{'shelfname'}=$shelfname;
+ $shelflist{$shelfnumber}->{'count'}=$count;
+ $shelflist{$shelfnumber}->{'owner'}=$owner;
+ $shelflist{$shelfnumber}->{'surname'} = $surname;
+ $shelflist{$shelfnumber}->{'firstname'} = $firstname;
+ $shelflist{$shelfnumber}->{'category'} = $category;
+
+
+ }
+
+ return(\%shelflist);
+}
+
+=item GetShelfContents
+
+ $itemlist = &GetShelfContents($env, $shelfnumber);
+
+Looks up information about the contents of virtual bookshelf number
+C<$shelfnumber>.
+
+Returns a reference-to-array, whose elements are references-to-hash,
+as returned by C<&getiteminformation>.
+
+I don't know what C<$env> is.
+
+=cut
+#'
+sub GetShelfContents {
+ my ($env, $shelfnumber) = @_;
+ my @itemlist;
+ my $sth=$dbh->prepare("select itemnumber from shelfcontents where shelfnumber=? order by itemnumber");
+ $sth->execute($shelfnumber);
+ while (my ($itemnumber) = $sth->fetchrow) {
+ my ($item) = getiteminformation($env, $itemnumber, 0);
+ push (@itemlist, $item);
+ }
+ return (\@itemlist);
+}
+
+=item AddToShelf
+
+ &AddToShelf($env, $itemnumber, $shelfnumber);
+
+Adds item number C<$itemnumber> to virtual bookshelf number
+C<$shelfnumber>, unless that item is already on that shelf.
+
+C<$env> is ignored.
+
+=cut
+#'
+sub AddToShelf {
+ my ($env, $itemnumber, $shelfnumber) = @_;
+ return unless $itemnumber;
+ my $sth=$dbh->prepare("select * from shelfcontents where shelfnumber=? and itemnumber=?");
+
+ $sth->execute($shelfnumber, $itemnumber);
+ if ($sth->rows) {
+# already on shelf
+ } else {
+ $sth=$dbh->prepare("insert into shelfcontents (shelfnumber, itemnumber, flags) values (?, ?, 0)");
+ $sth->execute($shelfnumber, $itemnumber);
+ }
+}
+sub AddToShelfFromBiblio {
+ my ($env, $biblionumber, $shelfnumber) = @_;
+ return unless $biblionumber;
+ my $sth = $dbh->prepare("select itemnumber from items where biblionumber=?");
+ $sth->execute($biblionumber);
+ my ($itemnumber) = $sth->fetchrow;
+ $sth=$dbh->prepare("select * from shelfcontents where shelfnumber=? and itemnumber=?");
+ $sth->execute($shelfnumber, $itemnumber);
+ if ($sth->rows) {
+# already on shelf
+ } else {
+ $sth=$dbh->prepare("insert into shelfcontents (shelfnumber, itemnumber, flags,biblionumber) values (?, ?, 0,?)");
+ $sth->execute($shelfnumber, $itemnumber,$biblionumber);
+ }
+}
+
+=item RemoveFromShelf
+
+ &RemoveFromShelf($env, $itemnumber, $shelfnumber);
+
+Removes item number C<$itemnumber> from virtual bookshelf number
+C<$shelfnumber>. If the item wasn't on that bookshelf to begin with,
+nothing happens.
+
+C<$env> is ignored.
+
+=cut
+#'
+sub RemoveFromShelf {
+ my ($env, $itemnumber, $shelfnumber) = @_;
+ my $sth=$dbh->prepare("delete from shelfcontents where shelfnumber=? and itemnumber=?");
+ $sth->execute($shelfnumber,$itemnumber);
+}
+
+=item AddShelf
+
+ ($status, $msg) = &AddShelf($env, $shelfname);
+
+Creates a new virtual bookshelf with name C<$shelfname>.
+
+Returns a two-element array, where C<$status> is 0 if the operation
+was successful, or non-zero otherwise. C<$msg> is "Done" in case of
+success, or an error message giving the reason for failure.
+
+C<$env> is ignored.
+
+=cut
+#'
+# FIXME - Perhaps this could/should return the number of the new bookshelf
+# as well?
+sub AddShelf {
+ my ($env, $shelfname,$owner,$category) = @_;
+ my $sth=$dbh->prepare("select * from bookshelf where shelfname=?");
+ $sth->execute($shelfname);
+ if ($sth->rows) {
+ return(1, "Shelf \"$shelfname\" already exists");
+ } else {
+ $sth=$dbh->prepare("insert into bookshelf (shelfname,owner,category) values (?,?,?)");
+ $sth->execute($shelfname,$owner,$category);
+ return (0, "Done");
+ }
+}
+
+=item RemoveShelf
+
+ ($status, $msg) = &RemoveShelf($env, $shelfnumber);
+
+Deletes virtual bookshelf number C<$shelfnumber>. The bookshelf must
+be empty.
+
+Returns a two-element array, where C<$status> is 0 if the operation
+was successful, or non-zero otherwise. C<$msg> is "Done" in case of
+success, or an error message giving the reason for failure.
+
+C<$env> is ignored.
+
+=cut
+#'
+sub RemoveShelf {
+ my ($env, $shelfnumber) = @_;
+ my $sth=$dbh->prepare("select count(*) from shelfcontents where shelfnumber=?");
+ $sth->execute($shelfnumber);
+ my ($count)=$sth->fetchrow;
+ if ($count) {
+ return (1, "Shelf has $count items on it. Please remove all items before deleting this shelf.");
+ } else {
+ $sth=$dbh->prepare("delete from bookshelf where shelfnumber=?");
+ $sth->execute($shelfnumber);
+ return (0, "Done");
+ }
+}
+
+sub GetShelfListOfExt {
+ my ($owner) = @_;
+ my $sth;
+ if ($owner) {
+ $sth = $dbh->prepare("SELECT * FROM bookshelf WHERE (owner = ?) or category>=2 ORDER BY shelfname");
+ $sth->execute($owner);
+ } else {
+ $sth = $dbh->prepare("SELECT * FROM bookshelf where category<2 ORDER BY shelfname");
+ $sth->execute();
+ }
+
+ my $sth2 = $dbh->prepare("SELECT count(biblionumber) as bibliocount FROM shelfcontents WHERE (shelfnumber = ?)");
+
+ my @results;
+ while (my $row = $sth->fetchrow_hashref) {
+ $sth2->execute($row->{'shelfnumber'});
+ $row->{'bibliocount'} = $sth2->fetchrow;
+ if ($row->{'category'} == 1) {
+ $row->{'private'} = 1;
+ } else {
+ $row->{'public'} = 1;
+ }
+ push @results, $row;
+ }
+ return \@results;
+}
+
+sub GetShelfListExt {
+ my ($owner,$mincategory,$id_intitution, $intra) = @_;
+
+ my $sth1 = $dbh->prepare("SELECT * FROM careers WHERE id_institution = ?");
+ $sth1->execute($id_intitution);
+ my @results;
+
+ my $total_shelves = 0;
+ while (my $row1 = $sth1->fetchrow_hashref) {
+
+ my @shelves;
+ my $sth2;
+ if ($intra) {
+ $sth2=$dbh->prepare("SELECT
+ bookshelf.shelfnumber, bookshelf.shelfname,owner,surname,firstname, category,
+ count(shelfcontents.biblionumber) as count
+ FROM
+ bookshelf
+ LEFT JOIN shelfcontents ON bookshelf.shelfnumber = shelfcontents.shelfnumber
+ LEFT JOIN borrowers ON bookshelf.owner = borrowers.borrowernumber
+ LEFT JOIN bookshelves_careers ON bookshelves_careers.shelfnumber = bookshelf.shelfnumber
+ WHERE
+ (id_career = ?)
+ GROUP BY bookshelf.shelfnumber
+ ORDER BY shelfname");
+ $sth2->execute($row1->{'id_career'});
+
+ } else {
+ $sth2=$dbh->prepare("SELECT
+ bookshelf.shelfnumber, bookshelf.shelfname,owner,surname,firstname, category,
+ count(shelfcontents.biblionumber) as count
+ FROM
+ bookshelf
+ LEFT JOIN shelfcontents ON bookshelf.shelfnumber = shelfcontents.shelfnumber
+ LEFT JOIN borrowers ON bookshelf.owner = borrowers.borrowernumber
+ LEFT JOIN bookshelves_careers ON bookshelves_careers.shelfnumber = bookshelf.shelfnumber
+ WHERE
+ (owner = ? OR category >= ?) AND (id_career = ?)
+ GROUP BY bookshelf.shelfnumber
+ ORDER BY shelfname");
+ $sth2->execute($owner,$mincategory,$row1->{'id_career'});
+ }
+
+ $row1->{'shelfcount'} = 0;
+ while (my $row2 = $sth2->fetchrow_hashref) {
+ if ($owner == $row2->{'owner'}) {
+ $row2->{'canmanage'} = 1;
+ }
+ if ($row2->{'category'} == 1) {
+ $row2->{'private'} = 1;
+ } else {
+ $row2->{'public'} = 1;
+ }
+ $row1->{'shelfcount'}++;
+ $total_shelves++;
+ push @shelves, $row2;
+ }
+ $row1->{'shelvesloop'} = \@shelves;
+ push @results, $row1;
+ }
+
+ return($total_shelves, \@results);
+}
+
+sub AddShelfExt {
+ my ($shelfname,$owner,$category,$careers) = @_;
+ my $sth = $dbh->prepare("SELECT * FROM bookshelf WHERE shelfname = ?");
+ $sth->execute($shelfname);
+ if ($sth->rows) {
+ return 0;
+ } else {
+ $sth = $dbh->prepare("INSERT INTO bookshelf (shelfname,owner,category) VALUES (?,?,?)");
+ $sth->execute($shelfname,$owner,$category);
+ my $shelfnumber = $dbh->{'mysql_insertid'};
+
+ foreach my $row (@{$careers}) {
+ $sth = $dbh->prepare("INSERT INTO bookshelves_careers VALUES (?,?)");
+ $sth->execute($shelfnumber, $row);
+ }
+ return $shelfnumber;
+ }
+}
+
+sub EditShelfExt {
+ my ($shelfnumber,$shelfname,$category,$careers) = @_;
+ my $sth = $dbh->prepare("SELECT * FROM bookshelf WHERE shelfname = ? AND NOT shelfnumber = ? ");
+ $sth->execute($shelfname, $shelfnumber);
+ if ($sth->rows) {
+ return 0;
+ } else {
+ $sth = $dbh->prepare("UPDATE bookshelf SET shelfname = ?, category = ? WHERE shelfnumber = ?");
+ $sth->execute($shelfname,$category,$shelfnumber);
+
+ $sth = $dbh->prepare("DELETE FROM bookshelves_careers WHERE shelfnumber = ?");
+ $sth->execute($shelfnumber);
+
+ foreach my $row (@{$careers}) {
+ $sth = $dbh->prepare("INSERT INTO bookshelves_careers VALUES (?,?)");
+ $sth->execute($shelfnumber, $row);
+ }
+ return $shelfnumber;
+ }
+}
+
+
+sub RemoveShelfExt {
+ my ($shelfnumber) = @_;
+ my $sth = $dbh->prepare("DELETE FROM bookshelves_careers WHERE shelfnumber = ?");
+ $sth->execute($shelfnumber);
+ my $sth = $dbh->prepare("DELETE FROM shelfcontents WHERE shelfnumber = ?");
+ $sth->execute($shelfnumber);
+ $sth = $dbh->prepare("DELETE FROM bookshelf WHERE shelfnumber = ?");
+ $sth->execute($shelfnumber);
+ return 1;
+}
+
+sub GetShelfInfo {
+ my ($shelfnumber, $owner) = @_;
+ my $sth = $dbh->prepare("SELECT * FROM bookshelf WHERE shelfnumber = ?");
+ $sth->execute($shelfnumber);
+ my $result = $sth->fetchrow_hashref;
+
+ if ($result->{'owner'} == $owner) {
+ $result->{'canmanage'} = 1;
+ }
+
+ my $sth = $dbh->prepare("SELECT id_career FROM bookshelves_careers WHERE shelfnumber = ?");
+ $sth->execute($shelfnumber);
+ my @careers;
+ while (my $row = $sth->fetchrow) {
+ push @careers, $row;
+ }
+ $result->{'careers'} = \@careers;
+ return $result;
+}
+
+sub GetShelfContentsExt {
+ my ($shelfnumber) = @_;
+ my $sth = $dbh->prepare("SELECT biblionumber FROM shelfcontents WHERE shelfnumber = ? ORDER BY biblionumber");
+ $sth->execute($shelfnumber);
+ my @biblios;
+ my $even = 0;
+ while (my ($biblionumber) = $sth->fetchrow) {
+ my $biblio=ZEBRA_readyXML_noheader($dbh,$biblionumber);
+ my $xmlrecord=XML_xml2hash($biblio);
+ push @biblios,$xmlrecord;
+ }
+my ($facets, at results)=parsefields($dbh,"opac", at biblios);
+
+ return (\@results);
+}
+
+sub RemoveFromShelfExt {
+ my ($biblionumber, $shelfnumber) = @_;
+ my $sth = $dbh->prepare("DELETE FROM shelfcontents WHERE shelfnumber = ? AND biblionumber = ?");
+ $sth->execute($shelfnumber,$biblionumber);
+}
+
+sub AddToShelfExt {
+ my ($biblionumber, $shelfnumber) = @_;
+ my $sth = $dbh->prepare("SELECT * FROM shelfcontents WHERE shelfnumber = ? AND biblionumber = ?");
+ $sth->execute($shelfnumber, $biblionumber);
+ if ($sth->rows) {
+ return 0
+ } else {
+ $sth = $dbh->prepare("INSERT INTO shelfcontents (shelfnumber, biblionumber) VALUES (?, ?)");
+ $sth->execute($shelfnumber, $biblionumber);
+ }
+}
+
+sub AddRequestToShelf {
+ my ($shelfnumber, $requestType, $requestName, $comments) = @_;
+ my $sth = $dbh->prepare("INSERT INTO shelf_requests (shelfnumber, request_name, request_type, status, request_date, comments) VALUES (?,?,?,?, CURRENT_DATE(),?)");
+ $sth->execute($shelfnumber, $requestName, $requestType, "PENDING", $comments);
+ return $dbh->{'mysql_insertid'};
+}
+
+sub CountShelfRequest {
+ my ($shelfnumber, $status) = @_;
+ my $sth;
+ if ($shelfnumber) {
+ $sth = $dbh->prepare("SELECT count(idRequest) FROM shelf_requests WHERE shelfnumber = ? AND status = ?");
+ $sth->execute($shelfnumber, $status);
+ } else {
+ $sth = $dbh->prepare("SELECT count(idRequest) FROM shelf_requests WHERE status = ?");
+ $sth->execute($status);
+ }
+ my ($count) = $sth->fetchrow_array;
+ return $count;
+}
+
+sub GetShelfRequests {
+ my ($shelfnumber, $status, $type) = @_;
+ my @params;
+ my $query = "SELECT * FROM shelf_requests SR INNER JOIN bookshelf BS ON SR.shelfnumber = BS.shelfnumber WHERE status = ?";
+ push @params, $status;
+ if ($shelfnumber) {
+ $query.= " AND shelfnumber = ?";
+ push @params, $shelfnumber;
+ }
+ if ($type) {
+ $query.= " AND request_type = ?";
+ push @params, $type;
+ }
+ $query.= " ORDER BY SR.shelfnumber, SR.request_date";
+ my $sth = $dbh->prepare($query);
+ $sth->execute(@params);
+ my @results;
+
+ my $color = 0;
+ while (my $row = $sth->fetchrow_hashref) {
+ my $borrdata = borrdata('',$row->{'owner'});
+ $row->{'surname'} = $borrdata->{'surname'};
+ $row->{'firstname'} = $borrdata->{'firstname'};
+ $row->{'cardnumber'} = $borrdata->{'cardnumber'};
+ $row->{'request_date'} = format_date($row->{'request_date'});
+ $row->{$row->{'request_type'}} = 1;
+ $row->{$row->{'status'}} = 1;
+ $row->{'color'} = $color = not $color;
+ push @results, $row;
+ }
+ return (\@results);
+}
+
+sub RejectShelfRequest {
+ my ($idRequest) = @_;
+ #get the type and name request
+ my $sth = $dbh->prepare("SELECT request_type, request_name FROM shelf_requests WHERE idRequest = ?");
+ $sth->execute($idRequest);
+ my ($request_type, $request_name) = $sth->fetchrow_array;
+ #if the request is a file, then unlink the file
+ if ($request_type eq 'file') {
+ unlink($ENV{'DOCUMENT_ROOT'}."/uploaded-files/shelf-files/$idRequest-$request_name");
+ }
+ #change tha request status to REJECTED
+ $sth = $dbh->prepare("UPDATE shelf_requests SET status = ? WHERE idRequest = ?");
+ $sth->execute("REJECTED", $idRequest);
+ return 1;
+}
+
+sub GetShelfRequestOwner {
+ my ($idRequest) = @_;
+ my $sth = $dbh->prepare("SELECT owner FROM shelf_requests R INNER JOIN bookshelf S ON R.shelfnumber = S.shelfnumber WHERE idRequest = ?");
+ $sth->execute($idRequest);
+ my ($owner) = $sth->fetchrow_array;
+ my $bordata = &borrdata(undef, $owner);
+ #print "Content-type: text/plain \n\n --- $owner ----- $bordata->{'emailaddress'}" ;
+ return ($bordata);
+}
+
+sub GetShelfRequest {
+ my ($idRequest) = @_;
+ my $sth = $dbh->prepare("SELECT * FROM shelf_requests R INNER JOIN bookshelf S ON R.shelfnumber = S.shelfnumber WHERE idRequest = ?");
+ $sth->execute($idRequest);
+ my $request_data = $sth->fetchrow_hashref;
+ return $request_data;
+}
+
+sub CatalogueShelfRequest {
+ my ($idRequest, $shelfnumber, $biblionumber) = @_;
+ #find the last request status
+ my $sth = $dbh->prepare("SELECT status, biblionumber FROM shelf_requests WHERE idRequest = ?");
+ $sth->execute($idRequest);
+ my ($prev_status, $prev_biblionumber) = $sth->fetchrow_array;
+ #if the status was not seted, inserts an entry in shelfcontents
+ if ($prev_status ne "CATALOGUED") {
+ $sth = $dbh->prepare("INSERT INTO shelfcontents (shelfnumber, biblionumber) VALUES (?,?)");
+ $sth->execute($shelfnumber, $biblionumber);
+ #if the request was previously catalogued, delete the entry in shelfcontens
+ } elsif ($prev_status ne "REJECTED") {
+ $sth = $dbh->prepare("DELETE FROM shelfcontents WHERE shelfnumber = ? AND biblionumber = ?");
+ $sth->execute($shelfnumber, $prev_biblionumber);
+ }
+ #change the status to catalogued
+ $sth = $dbh->prepare("UPDATE shelf_requests SET status = ?, biblionumber = ? WHERE idRequest = ?");
+ $sth->execute("CATALOGUED", $biblionumber, $idRequest);
+ return 1;
+}
+
+END { } # module clean-up code here (global destructor)
+
+1;
+
+#
+# $Log: BookShelves.pm,v $
+# Revision 1.1.2.1 2007/03/10 01:35:34 tgarip1957
+# fresh files for rel_TG
+#
+# Revision 1.19 2006/11/06 21:01:43 tgarip1957
+# Bug fixing and complete removal of Date::Manip
+#
+# Revision 1.18 2006/09/06 16:21:03 tgarip1957
+# Clean up before final commits
+#
+# Revision 1.13 2004/03/11 16:06:20 tipaul
+# *** empty log message ***
+#
+# Revision 1.11.2.2 2004/02/19 10:15:41 tipaul
+# new feature : adding book to bookshelf from biblio detail screen.
+#
+# Revision 1.11.2.1 2004/02/06 14:16:55 tipaul
+# fixing bugs in bookshelves management.
+#
+# Revision 1.11 2003/12/15 10:57:08 slef
+# DBI call fix for bug 662
+#
+# Revision 1.10 2003/02/05 10:05:02 acli
+# Converted a few SQL statements to use ? to fix a few strange SQL errors
+# Noted correct tab size
+#
+# Revision 1.9 2002/10/13 08:29:18 arensb
+# Deleted unused variables.
+# Removed trailing whitespace.
+#
+# Revision 1.8 2002/10/10 04:32:44 arensb
+# Simplified references.
+#
+# Revision 1.7 2002/10/05 09:50:10 arensb
+# Merged with arensb-context branch: use C4::Context->dbh instead of
+# &C4Connect, and generally prefer C4::Context over C4::Database.
+#
+# Revision 1.6.2.1 2002/10/04 02:24:43 arensb
+# Use C4::Connect instead of C4::Database, C4::Connect->dbh instead
+# C4Connect.
+#
+# Revision 1.6 2002/09/23 13:50:30 arensb
+# Fixed missing bit in POD.
+#
+# Revision 1.5 2002/09/22 17:29:17 arensb
+# Added POD.
+# Added some FIXME comments.
+# Removed useless trailing whitespace.
+#
+# Revision 1.4 2002/08/14 18:12:51 tonnesen
+# Added copyright statement to all .pl and .pm files
+#
+# Revision 1.3 2002/07/02 17:48:06 tonnesen
+# Merged in updates from rel-1-2
+#
+# Revision 1.2.2.1 2002/06/26 20:46:48 tonnesen
+# Inserting some changes I made locally a while ago.
+#
+#
+1;
+__END__
+
+
+=back
+
+=head1 AUTHOR
+
+Koha Developement team <info at koha.org>
+
+=head1 SEE ALSO
+
+C4::Circulation::Circ2(3)
+
+=cut
Index: Bookfund.pm
===================================================================
RCS file: Bookfund.pm
diff -N Bookfund.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Bookfund.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,571 @@
+package C4::Bookfund;
+
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+# $Id: Bookfund.pm,v 1.1.2.1 2007/03/10 01:35:34 tgarip1957 Exp $
+
+use strict;
+require Exporter;
+
+use vars qw($VERSION @ISA @EXPORT);
+
+# set the version for version checking
+$VERSION = do { my @v = '$Revision: 1.1.2.1 $' =~ /\d+/g; shift(@v) . "." . join( "_", map { sprintf "%03d", $_ } @v ); };
+
+=head1 NAME
+
+C4::Bookfund - Koha functions for dealing with bookfund, currency & money.
+
+=head1 SYNOPSIS
+
+use C4::Bookfund;
+
+=head1 DESCRIPTION
+
+the functions in this modules deal with bookfund, currency and money.
+They allow to get and/or set some informations for a specific budget or currency.
+
+=cut
+
+ at ISA = qw(Exporter);
+ at EXPORT = qw(
+ &GetBookFund &GetBookFunds &GetBookFundsId &GetBookFundBreakdown &GetCurrencies
+ &NewBookFund
+ &ModBookFund &ModCurrencies
+ &SearchBookFund
+ &Countbookfund
+ &ConvertCurrency
+ &DelBookFund
+);
+
+=head1 FUNCTIONS
+
+=over 2
+
+=cut
+
+#-------------------------------------------------------------#
+
+=head3 GetBookFund
+
+=over 4
+
+$dataaqbookfund = &GetBookFund($bookfundid);
+
+this function get the bookfundid, bookfundname, the bookfundgroup, the branchcode
+from aqbookfund table for bookfundid given on input arg.
+return:
+C<$dataaqbookfund> is a hashref full of bookfundid, bookfundname, bookfundgroup,
+and branchcode.
+
+=back
+
+=cut
+
+sub GetBookFund {
+ my $bookfundid = shift;
+ my $dbh = C4::Context->dbh;
+ my $query = "
+ SELECT
+ bookfundid,
+ bookfundname,
+ bookfundgroup,
+ branchcode
+ FROM aqbookfund
+ WHERE bookfundid = ?
+ ";
+ my $sth=$dbh->prepare($query);
+$sth->execute($bookfundid);
+ return $sth->fetchrow_hashref;
+}
+
+
+=head3 GetBookFundsId
+
+=over 4
+
+$sth = &GetBookFundsId
+Read on aqbookfund table and execute a simple SQL query.
+
+return:
+$sth->execute. Don't forget to fetch row from the database after using
+this function by using, for example, $sth->fetchrow_hashref;
+
+C<@results> is an array of id existing on the database.
+
+=back
+
+=cut
+
+sub GetBookFundsId {
+ my @bookfundids_loop;
+ my $dbh= C4::Context->dbh;
+ my $query = "
+ SELECT bookfundid
+ FROM aqbookfund
+ ";
+ my $sth = $dbh->prepare($query);
+ $sth->execute;
+ return $sth;
+}
+
+#-------------------------------------------------------------#
+
+=head3 GetBookFunds
+
+=over 4
+
+ at results = &GetBookFunds;
+
+Returns a list of all book funds.
+
+C<@results> is an array of references-to-hash, whose keys are fields from the aqbookfund and aqbudget tables of the Koha database. Results are ordered
+alphabetically by book fund name.
+
+=back
+
+=cut
+
+sub GetBookFunds {
+ my ($branch) = @_;
+ my $dbh = C4::Context->dbh;
+ my $userenv = C4::Context->userenv;
+ my $branch = $userenv->{branch};
+ my $strsth;
+
+ if ( $branch ) {
+ $strsth = "
+ SELECT *
+ FROM aqbookfund,aqbudget
+ WHERE aqbookfund.bookfundid=aqbudget.bookfundid
+ AND startdate<=now()
+ AND enddate>now()
+ AND (aqbookfund.branchcode IS NULL OR aqbookfund.branchcode='' OR aqbookfund.branchcode= ? )
+ GROUP BY aqbookfund.bookfundid ORDER BY bookfundname";
+ }
+ else {
+ $strsth = "
+ SELECT *
+ FROM aqbookfund,
+ aqbudget
+ WHERE aqbookfund.bookfundid=aqbudget.bookfundid
+ AND startdate<now()
+ AND enddate>now()
+ GROUP BY aqbookfund.bookfundid ORDER BY bookfundname
+ ";
+ }
+ my $sth = $dbh->prepare($strsth);
+ if ( $branch ) {
+ $sth->execute($branch);
+ }
+ else {
+ $sth->execute;
+ }
+ my @results = ();
+ while ( my $data = $sth->fetchrow_hashref ) {
+ push( @results, $data );
+ }
+ $sth->finish;
+ return @results;
+}
+
+#-------------------------------------------------------------#
+
+=head3 GetCurrencies
+
+=over 4
+
+ at currencies = &GetCurrencies;
+
+Returns the list of all known currencies.
+
+C<$currencies> is a array; its elements are references-to-hash, whose
+keys are the fields from the currency table in the Koha database.
+
+=back
+
+=cut
+
+sub GetCurrencies {
+ my $dbh = C4::Context->dbh;
+ my $query = "
+ SELECT *
+ FROM currency
+ ";
+ my $sth = $dbh->prepare($query);
+ $sth->execute;
+ my @results = ();
+ while ( my $data = $sth->fetchrow_hashref ) {
+ push( @results, $data );
+ }
+ $sth->finish;
+ return @results;
+}
+
+#-------------------------------------------------------------#
+
+=head3 GetBookFundBreakdown
+
+=over 4
+
+( $spent, $comtd ) = &GetBookFundBreakdown( $id, $year, $start, $end );
+
+returns the total comtd & spent for a given bookfund, and a given year
+used in acqui-home.pl
+
+=back
+
+=cut
+
+sub GetBookFundBreakdown {
+ my ( $id, $year, $start, $end ) = @_;
+ my $dbh = C4::Context->dbh;
+
+ # if no start/end dates given defaut to everything
+ if ( !$start ) {
+ $start = '0000-00-00';
+ $end = 'now()';
+ }
+
+ # do a query for spent totals.
+ my $query = "
+ SELECT quantity,datereceived,freight,unitprice,listprice,ecost,
+ quantityreceived,subscription
+ FROM aqorders
+ LEFT JOIN aqorderbreakdown ON aqorders.ordernumber=aqorderbreakdown.ordernumber
+ WHERE bookfundid=?
+ AND (datecancellationprinted IS NULL OR datecancellationprinted='0000-00-00')
+ AND ((datereceived >= ? and datereceived < ?) OR (budgetdate >= ? and budgetdate < ?))
+ ";
+ my $sth = $dbh->prepare($query);
+ $sth->execute( $id, $start, $end, $start, $end );
+
+ my $spent = 0;
+ while ( my $data = $sth->fetchrow_hashref ) {
+ if ( $data->{'subscription'} == 1 ) {
+ $spent += $data->{'quantity'} * $data->{'unitprice'};
+ }
+ else {
+
+ my $leftover = $data->{'quantity'} - $data->{'quantityreceived'};
+ $spent += ( $data->{'unitprice'} ) * $data->{'quantityreceived'};
+
+ }
+ }
+
+ # then do a seperate query for commited totals, (pervious single query was
+ # returning incorrect comitted results.
+
+ my $query = "
+ SELECT quantity,datereceived,freight,unitprice,
+ listprice,ecost,quantityreceived AS qrev,
+ subscription,biblio.title,itemtype,aqorders.biblionumber,
+ aqorders.booksellerinvoicenumber,
+ quantity-quantityreceived AS tleft,
+ aqorders.ordernumber AS ordnum,entrydate,budgetdate,
+ booksellerid,aqbasket.basketno
+ FROM aqorderbreakdown,
+ aqbasket,
+ aqorders
+ LEFT JOIN biblio ON biblio.biblionumber=aqorders.biblionumber
+ WHERE bookfundid=?
+ AND aqorders.ordernumber=aqorderbreakdown.ordernumber
+ AND aqorders.basketno=aqbasket.basketno
+ AND (budgetdate >= ? AND budgetdate < ?)
+ AND (datecancellationprinted IS NULL OR datecancellationprinted='0000-00-00')
+ ";
+
+ my $sth = $dbh->prepare($query);
+ $sth->execute( $id, $start, $end );
+
+ my $comtd;
+
+ my $total = 0;
+ while ( my $data = $sth->fetchrow_hashref ) {
+ my $left = $data->{'tleft'};
+ if ( !$left || $left eq '' ) {
+ $left = $data->{'quantity'};
+ }
+ if ( $left && $left > 0 ) {
+ my $subtotal = $left * $data->{'ecost'};
+ $data->{subtotal} = $subtotal;
+ $data->{'left'} = $left;
+ $comtd += $subtotal;
+ }
+ }
+
+ $sth->finish;
+ return ( $spent, $comtd );
+}
+
+=head3 NewBookFund
+
+=over 4
+
+&NewBookFund(bookfundid, bookfundname, branchcode);
+
+this function create a new bookfund into the database.
+
+=back
+
+=cut
+
+sub NewBookFund{
+ my ($bookfundid, $bookfundname, $branchcode) = @_;
+ $branchcode = undef unless $branchcode;
+ my $dbh = C4::Context->dbh;
+ my $query = "
+ INSERT
+ INTO aqbookfund
+ (bookfundid, bookfundname, branchcode)
+ VALUES
+ (?, ?, ?)
+ ";
+ my $sth=$dbh->prepare($query);
+ $sth->execute($bookfundid,$bookfundname,$branchcode);
+}
+
+#-------------------------------------------------------------#
+
+=head3 ModBookFund
+
+=over 4
+
+&ModBookFund($bookfundname,$branchcode,$bookfundid);
+this function update the bookfundname and the branchcode on aqbookfund table
+on database.
+
+=back
+
+=cut
+
+sub ModBookFund {
+ my ($bookfundname,$branchcode,$bookfundid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = "
+ UPDATE aqbookfund
+ SET bookfundname = ?,
+ branchcode = ?
+ WHERE bookfundid = ?
+ ";
+ my $sth=$dbh->prepare($query);
+ $sth->execute($bookfundname,$branchcode,$bookfundid);
+# budgets depending on a bookfund must have the same branchcode
+# if the bookfund branchcode is set
+ if (defined $branchcode) {
+ $query = "
+ UPDATE aqbudget
+ SET branchcode = ?
+ ";
+ $sth=$dbh->prepare($query);
+ $sth->execute($branchcode);
+ }
+}
+
+#-------------------------------------------------------------#
+
+=head3 SearchBookFund
+
+=over 4
+ at results = SearchBookFund(
+ $bookfundid,$filter,$filter_bookfundid,
+ $filter_bookfundname,$filter_branchcode);
+
+this function searchs among the bookfunds corresponding to our filtering rules.
+
+=back
+
+=cut
+
+sub SearchBookFund {
+ my $dbh = C4::Context->dbh;
+ my ($filter,
+ $filter_bookfundid,
+ $filter_bookfundname,
+ $filter_branchcode
+ ) = @_;
+
+ my @bindings;
+
+ my $query = "
+ SELECT bookfundid,
+ bookfundname,
+ bookfundgroup,
+ branchcode
+ FROM aqbookfund
+ WHERE 1 = 1 ";
+
+ if ($filter) {
+ if ($filter_bookfundid) {
+ $query.= "AND bookfundid = ?";
+ push @bindings, $filter_bookfundid;
+ }
+ if ($filter_bookfundname) {
+ $query.= "AND bookfundname like ?";
+ push @bindings, '%'.$filter_bookfundname.'%';
+ }
+ if ($filter_branchcode) {
+ $query.= "AND branchcode = ?";
+ push @bindings, $filter_branchcode;
+ }
+ }
+ $query.= "ORDER BY bookfundid";
+
+ my $sth = $dbh->prepare($query);
+ $sth->execute(@bindings);
+ my @results;
+ while (my $row = $sth->fetchrow_hashref) {
+ push @results, $row;
+ }
+ return @results;
+}
+
+#-------------------------------------------------------------#
+
+=head3 ModCurrencies
+
+=over 4
+
+&ModCurrencies($currency, $newrate);
+
+Sets the exchange rate for C<$currency> to be C<$newrate>.
+
+=back
+
+=cut
+
+sub ModCurrencies {
+ my ( $currency, $rate ) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = "
+ UPDATE currency
+ SET rate=?
+ WHERE currency=?
+ ";
+ my $sth = $dbh->prepare($query);
+ $sth->execute( $rate, $currency );
+}
+
+#-------------------------------------------------------------#
+
+=head3 Countbookfund
+
+=over 4
+
+$number = Countbookfund($bookfundid);
+
+this function count the number of bookfund with id given on input arg.
+return :
+the result of the SQL query as a number.
+
+=back
+
+=cut
+
+sub Countbookfund {
+ my $bookfundid = shift;
+ my $dbh = C4::Context->dbh;
+ my $query ="
+ SELECT COUNT(*)
+ FROM aqbookfund
+ WHERE bookfundid = ?
+ ";
+ my $sth = $dbh->prepare($query);
+ $sth->execute($bookfundid);
+ return $sth->fetchrow;
+}
+
+
+#-------------------------------------------------------------#
+
+=head3 ConvertCurrency
+
+=over 4
+
+$foreignprice = &ConvertCurrency($currency, $localprice);
+
+Converts the price C<$localprice> to foreign currency C<$currency> by
+dividing by the exchange rate, and returns the result.
+
+If no exchange rate is found, C<&ConvertCurrency> assumes the rate is one
+to one.
+
+=back
+
+=cut
+
+sub ConvertCurrency {
+ my ( $currency, $price ) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = "
+ SELECT rate
+ FROM currency
+ WHERE currency=?
+ ";
+ my $sth = $dbh->prepare($query);
+ $sth->execute($currency);
+ my $cur = ( $sth->fetchrow_array() )[0];
+ if ( $cur == 0 ) {
+ $cur = 1;
+ }
+ return ( $price / $cur );
+}
+
+#-------------------------------------------------------------#
+
+=head3 DelBookFund
+
+=over 4
+
+&DelBookFund($bookfundid);
+this function delete a bookfund which has $bokfundid as parameter on aqbookfund table and delete the approriate budget.
+
+=back
+
+=cut
+
+sub DelBookFund {
+ my $bookfundid = shift;
+ my $dbh = C4::Context->dbh;
+ my $query = "
+ DELETE FROM aqbookfund
+ WHERE bookfundid=?
+ ";
+ my $sth=$dbh->prepare($query);
+ $sth->execute($bookfundid);
+ $sth->finish;
+ $query = "
+ DELETE FROM aqbudget where bookfundid=?
+ ";
+ $sth=$dbh->prepare($query);
+ $sth->execute($bookfundid);
+ $sth->finish;
+}
+
+
+1;
+
+__END__
+
+=back
+
+=head1 AUTHOR
+
+Koha Developement team <info at koha.org>
+
+=cut
Index: Bookseller.pm
===================================================================
RCS file: Bookseller.pm
diff -N Bookseller.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Bookseller.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,275 @@
+package C4::Bookseller;
+
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+# $Id: Bookseller.pm,v 1.1.2.1 2007/03/10 01:35:34 tgarip1957 Exp $
+
+use strict;
+require Exporter;
+use vars qw($VERSION @ISA @EXPORT);
+
+# set the version for version checking
+$VERSION = do { my @v = '$Revision: 1.1.2.1 $' =~ /\d+/g; shift(@v) . "." . join( "_", map { sprintf "%03d", $_ } @v ); };
+
+ at ISA = qw(Exporter);
+ at EXPORT = qw(
+ &GetBookSeller &GetBooksellersWithLateOrders
+ &ModBookseller
+ &AddBookseller
+);
+
+
+=head1 NAME
+
+C4::Bookseller - Koha functions for dealing with booksellers.
+
+=head1 SYNOPSIS
+
+use C4::Bookseller;
+
+=head1 DESCRIPTION
+
+The functions in this module deal with booksellers. They allow to
+add a new bookseller, to modify it or to get some informations around
+a bookseller.
+
+=head1 FUNCTIONS
+
+=over 2
+
+=cut
+
+#-------------------------------------------------------------------#
+
+=head3 GetBookSeller
+
+=over 4
+
+ at results = &GetBookSeller($searchstring);
+
+Looks up a book seller. C<$searchstring> may be either a book seller
+ID, or a string to look for in the book seller's name.
+
+C<@results> is an array of references-to-hash, whose keys are the fields of of the
+aqbooksellers table in the Koha database.
+
+=back
+
+=cut
+
+sub GetBookSeller {
+ my ($searchstring) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = "
+ SELECT *
+ FROM aqbooksellers
+ WHERE name LIKE ? OR id = ?
+ ";
+ my $sth =$dbh->prepare($query);
+ $sth->execute("$searchstring%", $searchstring );
+ my @results;
+ while ( my $data = $sth->fetchrow_hashref ) {
+ push( @results, $data );
+ }
+ $sth->finish;
+ return @results ;
+}
+
+
+#-----------------------------------------------------------------#
+
+=head3 GetBooksellersWithLateOrders
+
+=over 4
+
+%results = &GetBooksellersWithLateOrders;
+
+Searches for suppliers with late orders.
+
+=back
+
+=cut
+
+sub GetBooksellersWithLateOrders {
+ my $delay = shift;
+ my $dbh = C4::Context->dbh;
+
+# FIXME NOT quite sure that this operation is valid for DBMs different from Mysql, HOPING so
+# should be tested with other DBMs
+
+ my $strsth;
+ my $dbdriver = C4::Context->config("db_scheme") || "mysql";
+ if ( $dbdriver eq "mysql" ) {
+ $strsth = "
+ SELECT DISTINCT aqbasket.booksellerid, aqbooksellers.name
+ FROM aqorders, aqbasket
+ LEFT JOIN aqbooksellers ON aqbasket.booksellerid = aqbooksellers.id
+ WHERE aqorders.basketno = aqbasket.basketno
+ AND (closedate < DATE_SUB(CURDATE( ),INTERVAL $delay DAY)
+ AND (datereceived = '' OR datereceived IS NULL))
+ ";
+ }
+ else {
+ $strsth = "
+ SELECT DISTINCT aqbasket.booksellerid, aqbooksellers.name
+ FROM aqorders, aqbasket
+ LEFT JOIN aqbooksellers ON aqbasket.aqbooksellerid = aqbooksellers.id
+ WHERE aqorders.basketno = aqbasket.basketno
+ AND (closedate < (CURDATE( )-(INTERVAL $delay DAY)))
+ AND (datereceived = '' OR datereceived IS NULL))
+ ";
+ }
+
+ my $sth = $dbh->prepare($strsth);
+ $sth->execute;
+ my %supplierlist;
+ while ( my ( $id, $name ) = $sth->fetchrow ) {
+ $supplierlist{$id} = $name;
+ }
+
+ return %supplierlist;
+}
+
+#--------------------------------------------------------------------#
+
+=head3 AddBookseller
+
+=over 4
+
+$id = &AddBookseller($bookseller);
+
+Creates a new bookseller. C<$bookseller> is a reference-to-hash whose
+keys are the fields of the aqbooksellers table in the Koha database.
+All fields must be present.
+
+Returns the ID of the newly-created bookseller.
+
+=back
+
+=cut
+
+sub AddBookseller {
+ my ($data) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = "
+ INSERT INTO aqbooksellers
+ (
+ name, address1, address2, address3, address4,
+ postal, phone, fax, url, contact,
+ contpos, contphone, contfax, contaltphone, contemail,
+ contnotes, active, listprice, invoiceprice, gstreg,
+ listincgst,invoiceincgst, specialty, discount, invoicedisc,
+ nocalc, notes
+ )
+ VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
+ ";
+ my $sth = $dbh->prepare($query);
+ $sth->execute(
+ $data->{'name'}, $data->{'address1'},
+ $data->{'address2'}, $data->{'address3'},
+ $data->{'address4'}, $data->{'postal'},
+ $data->{'phone'}, $data->{'fax'},
+ $data->{'url'}, $data->{'contact'},
+ $data->{'contpos'}, $data->{'contphone'},
+ $data->{'contfax'}, $data->{'contaltphone'},
+ $data->{'contemail'}, $data->{'contnotes'},
+ $data->{'active'}, $data->{'listprice'},
+ $data->{'invoiceprice'}, $data->{'gstreg'},
+ $data->{'listincgst'}, $data->{'invoiceincgst'},
+ $data->{'specialty'}, $data->{'discount'},
+ $data->{'invoicedisc'}, $data->{'nocalc'},
+ $data->{'notes'}
+ );
+
+ # return the id of this new supplier
+ my $query = "
+ SELECT max(id)
+ FROM aqbooksellers
+ ";
+ my $sth = $dbh->prepare($query);
+ $sth->execute;
+ return scalar($sth->fetchrow);
+}
+
+#-----------------------------------------------------------------#
+
+=head3 ModSupplier
+
+=over 4
+
+&ModSupplier($bookseller);
+
+Updates the information for a given bookseller. C<$bookseller> is a
+reference-to-hash whose keys are the fields of the aqbooksellers table
+in the Koha database. It must contain entries for all of the fields.
+The entry to modify is determined by C<$bookseller-E<gt>{id}>.
+
+The easiest way to get all of the necessary fields is to look up a
+book seller with C<&booksellers>, modify what's necessary, then call
+C<&ModSupplier> with the result.
+
+=back
+
+=cut
+
+sub ModBookseller {
+ my ($data) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = "
+ UPDATE aqbooksellers
+ SET name=?,address1=?,address2=?,address3=?,address4=?,
+ postal=?,phone=?,fax=?,url=?,contact=?,contpos=?,
+ contphone=?,contfax=?,contaltphone=?,contemail=?,
+ contnotes=?,active=?,listprice=?, invoiceprice=?,
+ gstreg=?, listincgst=?,invoiceincgst=?,
+ specialty=?,discount=?,invoicedisc=?,nocalc=?, notes=?
+ WHERE id=?
+ ";
+ my $sth = $dbh->prepare($query);
+ $sth->execute(
+ $data->{'name'}, $data->{'address1'},
+ $data->{'address2'}, $data->{'address3'},
+ $data->{'address4'}, $data->{'postal'},
+ $data->{'phone'}, $data->{'fax'},
+ $data->{'url'}, $data->{'contact'},
+ $data->{'contpos'}, $data->{'contphone'},
+ $data->{'contfax'}, $data->{'contaltphone'},
+ $data->{'contemail'}, $data->{'contnotes'},
+ $data->{'active'}, $data->{'listprice'},
+ $data->{'invoiceprice'}, $data->{'gstreg'},
+ $data->{'listincgst'}, $data->{'invoiceincgst'},
+ $data->{'specialty'}, $data->{'discount'},
+ $data->{'invoicedisc'}, $data->{'nocalc'},
+ $data->{'notes'}, $data->{'id'}
+ );
+ $sth->finish;
+}
+
+
+
+1;
+
+__END__
+
+=back
+
+=head1 AUTHOR
+
+Koha Developement team <info at koha.org>
+
+=cut
Index: Boolean.pm
===================================================================
RCS file: Boolean.pm
diff -N Boolean.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Boolean.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,122 @@
+package C4::Boolean;
+
+# $Id: Boolean.pm,v 1.1.2.1 2007/03/10 01:35:34 tgarip1957 Exp $
+
+#package to handle Boolean values in the parameters table
+# Note: This is just a utility module; it should not be instantiated.
+
+
+# Copyright 2003 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+use POSIX;
+require Exporter;
+
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
+
+# set the version for version checking
+$VERSION = 0.01;
+
+=head1 NAME
+
+C4::Boolean - Convenience functions to handle boolean values
+in the parameter table
+
+=head1 SYNOPSIS
+
+ use C4::Boolean;
+
+=head1 DESCRIPTION
+
+In the parameter table, there are various Boolean values that
+variously require a 0/1, no/yes, false/true, or off/on values.
+This module aims to provide scripts a means to interpret these
+Boolean values in a consistent way which makes common sense.
+
+=head1 FUNCTIONS
+
+=over 2
+
+=cut
+
+ at ISA = qw(Exporter);
+ at EXPORT = (
+ &INVALID_BOOLEAN_STRING_EXCEPTION
+ );
+
+ at EXPORT_OK = qw(
+ true_p
+ );
+
+sub INVALID_BOOLEAN_STRING_EXCEPTION ()
+ { 'The given value does not seem to be interpretable as a Boolean value' }
+
+use vars qw( %strings );
+
+%strings = (
+ '0' => 0, '1' => 1, # C
+ '-1' => 1, # BASIC
+ 'nil' => 0, 't' => 1, # LISP
+ 'false' => 0, 'true' => 1, # Pascal
+ 'off' => 0, 'on' => 1,
+ 'no' => 0, 'yes' => 1,
+ 'n' => 0, 'y' => 1,
+);
+
+=item true_p
+
+ if ( C4::Boolean::true_p(C4::Context->preference("insecure")) ) {
+ ...
+ }
+
+Tries to interpret the passed string as a Boolean value. Returns
+the value if the string can be interpreted as such; otherwise an
+exception is thrown.
+
+=cut
+
+sub true_p ($) {
+ my($x) = @_;
+ my $it;
+ if (!defined $x || ref($x) ne '') {
+ die INVALID_BOOLEAN_STRING_EXCEPTION;
+ }
+ $x = lc($x);
+ $x =~ s/\s//g;
+ if (defined $strings{$x}) {
+ $it = $strings{$x};
+ } else {
+ die INVALID_BOOLEAN_STRING_EXCEPTION;
+ }
+ return $it;
+}
+
+
+#---------------------------------
+
+
+1;
+__END__
+
+=back
+
+=head1 AUTHOR
+
+Koha Developement team <info at koha.org>
+
+=cut
Index: Breeding.pm
===================================================================
RCS file: Breeding.pm
diff -N Breeding.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Breeding.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,200 @@
+package C4::Breeding;
+
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+use C4::Biblio;
+use C4::Search;
+use MARC::File::USMARC;
+use MARC::Record;
+use Encode;
+require Exporter;
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
+
+# set the version for version checking
+$VERSION = 0.01;
+
+=head1 NAME
+
+C4::Breeding : script to add a biblio in marc_breeding table.
+
+=head1 SYNOPSIS
+ &ImportBreeding($marcrecords,$overwrite_biblio,$filename,$z3950random);
+
+ C<$marcrecord> => the MARC::Record
+ C<$overwrite_biblio> => if set to 1 a biblio with the same ISBN will be overwritted.
+ if set to 0 a biblio with the same isbn will be ignored (the previous will be kept)
+ if set to -1 the biblio will be added anyway (more than 1 biblio with the same ISBN possible in the breeding
+ C<$encoding> => USMARC
+ or UNIMARC. used for char_decoding.
+ If not present, the parameter marcflavour is used instead
+ C<$z3950random> => the random value created during a z3950 search result.
+
+=head1 DESCRIPTION
+
+This is for depository of records coming from z3950 or directly imported.
+
+=cut
+
+ at ISA = qw(Exporter);
+ at EXPORT = qw(&ImportBreeding &BreedingSearch);
+
+sub ImportBreeding {
+ my ($marcrecords,$overwrite_biblio,$filename,$encoding,$z3950random) = @_;
+## use marc:batch send them in one by one
+# my @marcarray = split /\x1D/, $marcrecords;
+ my $dbh = C4::Context->dbh;
+my @kohafields;
+my @values;
+my @relations;
+my $sort;
+my @and_or;
+my @results;
+my $count;
+ my $searchbreeding = $dbh->prepare("select id from marc_breeding where isbn=? and title=?");
+ my $insertsql = $dbh->prepare("insert into marc_breeding (file,isbn,title,author,marc,encoding,z3950random,classification,subclass) values(?,?,?,?,?,?,?,?,?)");
+ my $replacesql = $dbh->prepare("update marc_breeding set file=?,isbn=?,title=?,author=?,marc=?,encoding=?,z3950random=?,classification=?,subclass=? where id=?");
+ $encoding = C4::Context->preference("marcflavour") unless $encoding;
+ # fields used for import results
+ my $imported=0;
+ my $alreadyindb = 0;
+ my $alreadyinfarm = 0;
+ my $notmarcrecord = 0;
+ my $breedingid;
+# for (my $i=0;$i<=$#marcarray;$i++) {
+ my $marcrecord = MARC::File::USMARC::decode($marcrecords);
+ my $marcxml=$marcrecord->as_xml_record($marcrecord);
+ $marcxml=Encode::encode('utf8',$marcxml);
+ my @warnings = $marcrecord->warnings();
+ if (scalar($marcrecord->fields()) == 0) {
+ $notmarcrecord++;
+ } else {
+ my $xmlhash=XML_xml2hash_onerecord($marcxml);
+ my $oldbiblio = XMLmarc2koha_onerecord($dbh,$xmlhash,'biblios');
+ # if isbn found and biblio does not exist, add it. If isbn found and biblio exists, overwrite or ignore depending on user choice
+ # drop every "special" char : spaces, - ...
+ $oldbiblio->{isbn} =~ s/ |-|\.//g,
+ $oldbiblio->{isbn} = substr($oldbiblio->{isbn},0,10);
+ $oldbiblio->{issn} =~ s/ |-|\.//g,
+ $oldbiblio->{issn} = substr($oldbiblio->{issn},0,10);
+ # search if biblio exists
+ my $biblioitemnumber;
+ my $facets;
+ if ( !$z3950random){
+ if ($oldbiblio->{isbn}) {
+ push @kohafields,"isbn";
+ push @values,$oldbiblio->{isbn};
+ push @relations,"";
+ push @and_or,"";
+
+ ($count,$facets, at results)=ZEBRAsearch_kohafields(\@kohafields,\@values,\@relations);
+ } else {
+ push @kohafields,"issn";
+ push @values,$oldbiblio->{issn};
+ push @relations,"";
+ push @and_or,"";
+ $sort="";
+ ($count,$facets, at results)=ZEBRAsearch_kohafields(\@kohafields,\@values,\@relations);
+ }
+ }
+ if ($count>0 && !$z3950random) {
+ $alreadyindb++;
+ } else {
+ # search in breeding farm
+
+ if ($oldbiblio->{isbn}) {
+ $searchbreeding->execute($oldbiblio->{isbn},$oldbiblio->{title});
+ ($breedingid) = $searchbreeding->fetchrow;
+ } elsif ($oldbiblio->{issn}){
+ $searchbreeding->execute($oldbiblio->{issn},$oldbiblio->{title});
+ ($breedingid) = $searchbreeding->fetchrow;
+ }
+ if ($breedingid && $overwrite_biblio eq 0) {
+ $alreadyinfarm++;
+ } else {
+ my $recoded=MARC::Record->new_from_xml($marcxml,"UTF-8");
+ $recoded->encoding('UTF-8');
+
+ if ($breedingid && $overwrite_biblio eq 1) {
+ $replacesql ->execute($filename,substr($oldbiblio->{isbn}.$oldbiblio->{issn},0,10),$oldbiblio->{title},$oldbiblio->{author},$recoded->as_usmarc,$encoding,$z3950random,$oldbiblio->{classification},$oldbiblio->{subclass},$breedingid);
+ } else {
+ $insertsql ->execute($filename,substr($oldbiblio->{isbn}.$oldbiblio->{issn},0,10),$oldbiblio->{title},$oldbiblio->{author},$recoded->as_usmarc,$encoding,$z3950random,$oldbiblio->{classification},$oldbiblio->{subclass});
+
+ $breedingid=$dbh->{'mysql_insertid'};
+ }
+ $imported++;
+ }
+ }
+ }
+ #}
+ return ($notmarcrecord,$alreadyindb,$alreadyinfarm,$imported,$breedingid);
+}
+
+
+=item BreedingSearch
+
+ ($count, @results) = &BreedingSearch($title,$isbn,$random);
+C<$title> contains the title,
+C<$isbn> contains isbn or issn,
+C<$random> contains the random seed from a z3950 search.
+
+C<$count> is the number of items in C<@results>. C<@results> is an
+array of references-to-hash; the keys are the items from the C<marc_breeding> table of the Koha database.
+
+=cut
+
+sub BreedingSearch {
+ my ($title,$isbn,$z3950random) = @_;
+ my $dbh = C4::Context->dbh;
+ my $count = 0;
+ my ($query, at bind);
+ my $sth;
+ my @results;
+
+ $query = "Select id,file,isbn,title,author,classification,subclass from marc_breeding where ";
+ if ($z3950random) {
+ $query .= "z3950random = ?";
+ @bind=($z3950random);
+ } else {
+ @bind=();
+ if ($title) {
+ $query .= "title like ?";
+ push(@bind,"$title%");
+ }
+ if ($title && $isbn) {
+ $query .= " and ";
+ }
+ if ($isbn) {
+ $query .= "isbn like ?";
+ push(@bind,"$isbn%");
+ }
+ }
+ $sth = $dbh->prepare($query);
+ $sth->execute(@bind);
+ while (my $data = $sth->fetchrow_hashref) {
+ $results[$count] = $data;
+ $count++;
+ } # while
+
+ $sth->finish;
+ return($count, @results);
+} # sub breedingsearch
+
+
+1;
+__END__
\ No newline at end of file
Index: Context.pm
===================================================================
RCS file: Context.pm
diff -N Context.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Context.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,952 @@
+# Copyright 2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+# $Id: Context.pm,v 1.1.2.1 2007/03/10 01:35:34 tgarip1957 Exp $
+package C4::Context;
+use strict;
+use DBI;
+use CGI;
+use C4::Boolean;
+use XML::Simple;
+require Exporter;
+use vars qw($VERSION $AUTOLOAD),
+ qw($context),
+ qw(@context_stack);
+
+$VERSION = do { my @v = '$Revision: 1.1.2.1 $' =~ /\d+/g;
+ shift(@v) . "." . join("_", map {sprintf "%03d", $_ } @v); };
+
+=head1 NAME
+
+C4::Context - Maintain and manipulate the context of a Koha script
+
+=head1 SYNOPSIS
+
+ use C4::Context;
+
+ use C4::Context("/path/to/koha.xml");
+
+ $config_value = C4::Context->config("config_variable");
+ $db_handle = C4::Context->dbh;
+ $stopwordhash = C4::Context->stopwords;
+
+=head1 DESCRIPTION
+
+When a Koha script runs, it makes use of a certain number of things:
+configuration settings in F</etc/koha.xml>, a connection to the Koha
+databases, and so forth. These things make up the I<context> in which
+the script runs.
+
+This module takes care of setting up the context for a script:
+figuring out which configuration file to load, and loading it, opening
+a connection to the right database, and so forth.
+
+Most scripts will only use one context. They can simply have
+
+ use C4::Context;
+
+at the top.
+
+Other scripts may need to use several contexts. For instance, if a
+library has two databases, one for a certain collection, and the other
+for everything else, it might be necessary for a script to use two
+different contexts to search both databases. Such scripts should use
+the C<&set_context> and C<&restore_context> functions, below.
+
+By default, C4::Context reads the configuration from
+F</etc/koha.xml>. This may be overridden by setting the C<$KOHA_CONF>
+environment variable to the pathname of a configuration file to use.
+
+=head1 METHODS
+
+=over 2
+
+=cut
+
+#'
+# In addition to what is said in the POD above, a Context object is a
+# reference-to-hash with the following fields:
+#
+# config
+# A reference-to-hash whose keys and values are the
+# configuration variables and values specified in the config
+# file (/etc/koha.xml).
+# dbh
+# A handle to the appropriate database for this context.
+# dbh_stack
+# Used by &set_dbh and &restore_dbh to hold other database
+# handles for this context.
+# Zconn
+# A connection object for the Zebra server
+
+use constant CONFIG_FNAME => "/etc/koha.xml";
+ # Default config file, if none is specified
+
+#$context = undef; # Initially, no context is set
+ at context_stack = (); # Initially, no saved contexts
+
+# read_config_file
+# Reads the specified Koha config file. Returns a reference-to-hash
+# whose keys are the configuration variables, and whose values are the
+# configuration values (duh).
+# Returns undef in case of error.
+#
+# Revision History:
+# 2004-08-10 A. Tarallo: Added code that checks if a variable is already
+# assigned and prints a message, otherwise create a new entry in the hash to
+# be returned.
+# Also added code that complaints if finds a line that isn't a variable
+# assignmet and skips the line.
+# Added a quick hack that makes the translation between the db_schema
+# and the DBI driver for that schema.
+#
+sub read_config_file
+{
+ my $fname = shift; # Config file to read
+
+ my $retval = {}; # Return value: ref-to-hash holding the
+ # configuration
+
+my $koha = XMLin($fname, keyattr => ['id'],forcearray => ['listen']);
+
+ return $koha;
+}
+
+# db_scheme2dbi
+# Translates the full text name of a database into de appropiate dbi name
+#
+sub db_scheme2dbi
+{
+ my $name = shift;
+
+ for ($name) {
+# FIXME - Should have other databases.
+ if (/mysql/i) { return("mysql"); }
+ if (/Postgres|Pg|PostgresSQL/) { return("Pg"); }
+ if (/oracle/i) { return("Oracle"); }
+ }
+ return undef; # Just in case
+}
+
+sub import
+{
+ my $package = shift;
+ my $conf_fname = shift; # Config file name
+ my $context;
+
+ # Create a new context from the given config file name, if
+ # any, then set it as the current context.
+ $context = new C4::Context($conf_fname);
+ return undef if !defined($context);
+ $context->set_context;
+}
+
+=item new
+
+ $context = new C4::Context;
+ $context = new C4::Context("/path/to/koha.xml");
+
+Allocates a new context. Initializes the context from the specified
+file, which defaults to either the file given by the C<$KOHA_CONF>
+environment variable, or F</etc/koha.xml>.
+
+C<&new> does not set this context as the new default context; for
+that, use C<&set_context>.
+
+=cut
+
+#'
+# Revision History:
+# 2004-08-10 A. Tarallo: Added check if the conf file is not empty
+sub new
+{
+ my $class = shift;
+ my $conf_fname = shift; # Config file to load
+ my $self = {};
+
+ # check that the specified config file exists and is not empty
+ undef $conf_fname unless
+ (defined $conf_fname && -e $conf_fname && -s $conf_fname);
+ # Figure out a good config file to load if none was specified.
+ if (!defined($conf_fname))
+ {
+ # If the $KOHA_CONF environment variable is set, use
+ # that. Otherwise, use the built-in default.
+ $conf_fname = $ENV{"KOHA_CONF"} || CONFIG_FNAME;
+ }
+ # Load the desired config file.
+ $self = read_config_file($conf_fname);
+ $self->{"config_file"} = $conf_fname;
+
+
+
+ warn "read_config_file($conf_fname) returned undef" if !defined($self->{"config"});
+ return undef if !defined($self->{"config"});
+
+ $self->{"dbh"} = undef; # Database handle
+ $self->{"mcgi"} = undef; # CGI handle
+ $self->{"Zconn"} = undef; # Zebra Connection
+ $self->{"Zconnauth"} = undef; # Zebra Connection for updating
+ $self->{"stopwords"} = undef; # stopwords list
+ $self->{"marcfromkohafield"} = undef; # the hash with relations between koha table fields and MARC field/subfield
+ $self->{"attrfromkohafield"} = undef; # the hash with relations between koha table fields and Bib1-attributes
+ $self->{"userenv"} = undef; # User env
+ $self->{"activeuser"} = undef; # current active user
+
+ bless $self, $class;
+ return $self;
+}
+
+=item set_context
+
+ $context = new C4::Context;
+ $context->set_context();
+or
+ set_context C4::Context $context;
+
+ ...
+ restore_context C4::Context;
+
+In some cases, it might be necessary for a script to use multiple
+contexts. C<&set_context> saves the current context on a stack, then
+sets the context to C<$context>, which will be used in future
+operations. To restore the previous context, use C<&restore_context>.
+
+=cut
+
+#'
+sub set_context
+{
+ my $self = shift;
+ my $new_context; # The context to set
+
+ # Figure out whether this is a class or instance method call.
+ #
+ # We're going to make the assumption that control got here
+ # through valid means, i.e., that the caller used an instance
+ # or class method call, and that control got here through the
+ # usual inheritance mechanisms. The caller can, of course,
+ # break this assumption by playing silly buggers, but that's
+ # harder to do than doing it properly, and harder to check
+ # for.
+ if (ref($self) eq "")
+ {
+ # Class method. The new context is the next argument.
+ $new_context = shift;
+ } else {
+ # Instance method. The new context is $self.
+ $new_context = $self;
+ }
+
+ # Save the old context, if any, on the stack
+ push @context_stack, $context if defined($context);
+
+ # Set the new context
+ $context = $new_context;
+}
+
+=item restore_context
+
+ &restore_context;
+
+Restores the context set by C<&set_context>.
+
+=cut
+
+#'
+sub restore_context
+{
+ my $self = shift;
+
+ if ($#context_stack < 0)
+ {
+ # Stack underflow.
+ die "Context stack underflow";
+ }
+
+ # Pop the old context and set it.
+ $context = pop @context_stack;
+
+ # FIXME - Should this return something, like maybe the context
+ # that was current when this was called?
+}
+
+=item config
+
+ $value = C4::Context->config("config_variable");
+
+ $value = C4::Context->config_variable;
+
+Returns the value of a variable specified in the configuration file
+from which the current context was created.
+
+The second form is more compact, but of course may conflict with
+method names. If there is a configuration variable called "new", then
+C<C4::Config-E<gt>new> will not return it.
+
+=cut
+
+#'
+sub config
+{
+ my $self = shift;
+ my $var = shift; # The config variable to return
+
+ return undef if !defined($context->{"config"});
+ # Presumably $self->{config} might be
+ # undefined if the config file given to &new
+ # didn't exist, and the caller didn't bother
+ # to check the return value.
+
+ # Return the value of the requested config variable
+ return $context->{"config"}->{$var};
+}
+=item zebraconfig
+$serverdir=C4::Context->zebraconfig("biblioserver")->{directory};
+
+returns the zebra server specific details for different zebra servers
+similar to C4:Context->config
+=cut
+
+sub zebraconfig
+{
+ my $self = shift;
+ my $var = shift; # The config variable to return
+
+ return undef if !defined($context->{"server"});
+ # Return the value of the requested config variable
+ return $context->{"server"}->{$var};
+}
+=item preference
+
+ $sys_preference = C4::Context->preference("some_variable");
+
+Looks up the value of the given system preference in the
+systempreferences table of the Koha database, and returns it. If the
+variable is not set, or in case of error, returns the undefined value.
+
+=cut
+
+#'
+# FIXME - The preferences aren't likely to change over the lifetime of
+# the script (and things might break if they did change), so perhaps
+# this function should cache the results it finds.
+sub preference
+{
+ my $self = shift;
+ my $var = shift; # The system preference to return
+ my $retval; # Return value
+ my $dbh = C4::Context->dbh; # Database handle
+ my $sth; # Database query handle
+
+ # Look up systempreferences.variable==$var
+ $retval = $dbh->selectrow_array(<<EOT);
+ SELECT value
+ FROM systempreferences
+ WHERE variable='$var'
+ LIMIT 1
+EOT
+ return $retval;
+}
+
+sub boolean_preference ($) {
+ my $self = shift;
+ my $var = shift; # The system preference to return
+ my $it = preference($self, $var);
+ return defined($it)? C4::Boolean::true_p($it): undef;
+}
+
+# AUTOLOAD
+# This implements C4::Config->foo, and simply returns
+# C4::Context->config("foo"), as described in the documentation for
+# &config, above.
+
+# FIXME - Perhaps this should be extended to check &config first, and
+# then &preference if that fails. OTOH, AUTOLOAD could lead to crappy
+# code, so it'd probably be best to delete it altogether so as not to
+# encourage people to use it.
+sub AUTOLOAD
+{
+ my $self = shift;
+
+ $AUTOLOAD =~ s/.*:://; # Chop off the package name,
+ # leaving only the function name.
+ return $self->config($AUTOLOAD);
+}
+
+=item Zconn
+
+$Zconn = C4::Context->Zconn
+$Zconnauth = C4::Context->Zconnauth
+Returns a connection to the Zebra database for the current
+context. If no connection has yet been made, this method
+creates one and connects.
+
+=cut
+
+sub Zconn {
+ my $self = shift;
+my $server=shift;
+my $syntax=shift;
+# if ( defined($context->{"Zconn"}->{$server}) ) {
+# return $context->{"Zconn"}->{$server};
+
+ # No connection object or it died. Create one.
+# } else {
+ $context->{"Zconn"} = &new_Zconn($server,$syntax);
+ return $context->{"Zconn"};
+# }
+}
+
+sub Zconnauth {
+ my $self = shift;
+my $server=shift;
+my $syntax=shift;
+ my $Zconnauth;
+##We destroy each connection made so create a new one
+ $context->{"Zconnauth"} = &new_Zconnauth($server,$syntax);
+ return $context->{"Zconnauth"};
+
+}
+
+
+
+=item new_Zconn
+
+Internal helper function. creates a new database connection from
+the data given in the current context and returns it.
+
+=cut
+
+sub new_Zconn {
+use ZOOM;
+my $server=shift;
+my $syntax=shift;
+$syntax="xml" unless $syntax;
+my $Zconn;
+my ($tcp,$host,$port)=split /:/,$context->{"listen"}->{$server}->{"content"};
+my $o = new ZOOM::Options();
+$o->option(async => 1);
+$o->option(preferredRecordSyntax => $syntax); ## in case we use MARC
+$o->option(databaseName=>$context->{"config"}->{$server});
+
+my $o2= new ZOOM::Options();
+
+ $Zconn=create ZOOM::Connection($o);
+ $Zconn->connect($host,$port);
+
+ return $Zconn;
+}
+
+## Zebra handler with write permission
+sub new_Zconnauth {
+use ZOOM;
+my $server=shift;
+my $syntax=shift;
+$syntax="xml" unless $syntax;
+my $Zconnauth;
+my ($tcp,$host,$port)=split /:/,$context->{"listen"}->{$server}->{"content"};
+my $o = new ZOOM::Options();
+#$o->option(async => 1);
+$o->option(preferredRecordSyntax => $syntax);
+$o->option(user=>$context->{"config"}->{"zebrauser"});
+$o->option(password=>$context->{"config"}->{"zebrapass"});
+$o->option(databaseName=>$context->{"config"}->{$server});
+ $o->option(charset=>"UTF8");
+ $Zconnauth=create ZOOM::Connection($o);
+$Zconnauth->connect($host,$port);
+return $Zconnauth;
+}
+
+## cgi handler
+sub mcgi {
+ my $self = shift;
+ if (defined($context->{"mcgi"})) {
+ return $context->{"mcgi"};
+ # No connection object or it died. Create one.
+ } else {
+
+ $context->{"mcgi"} = &_new_cgi();
+ return $context->{"mcgi"};
+ }
+}
+## _new_cgi creates a CGI handle
+
+sub _new_cgi{
+my $cgi=CGI->new();
+return $cgi;
+}
+
+# _new_dbh
+# Internal helper function (not a method!). This creates a new
+# database connection from the data given in the current context, and
+# returns it.
+sub _new_dbh
+{
+ ##correct name for db_schme
+ my $db_driver;
+ if ($context->config("db_scheme")){
+ $db_driver=db_scheme2dbi($context->config("db_scheme"));
+ }else{
+ $db_driver="mysql";
+ }
+
+ my $db_name = $context->config("database");
+ my $db_host = $context->config("hostname");
+ my $db_user = $context->config("user");
+ my $db_passwd = $context->config("pass");
+ my $dbh= DBI->connect("DBI:$db_driver:$db_name:$db_host",
+ $db_user, $db_passwd);
+ # Koha 3.0 is utf-8, so force utf8 communication between mySQL and koha, whatever the mysql default config.
+ $dbh->do("set NAMES 'utf8'");
+
+
+ return $dbh;
+}
+
+=item dbh
+
+ $dbh = C4::Context->dbh;
+
+Returns a database handle connected to the Koha database for the
+current context. If no connection has yet been made, this method
+creates one, and connects to the database.
+
+This database handle is cached for future use: if you call
+C<C4::Context-E<gt>dbh> twice, you will get the same handle both
+times. If you need a second database handle, use C<&new_dbh> and
+possibly C<&set_dbh>.
+
+=cut
+
+#'
+sub dbh
+{
+ my $self = shift;
+ if (defined($context->{"dbh"}) && !$ENV{MOD_PERL}) {
+ my $sth=$context->{"dbh"}->prepare("select 1");
+ return $context->{"dbh"} if (defined($sth->execute));
+ }
+ $context->{"dbh"} = &_new_dbh();
+ return $context->{"dbh"};
+}
+
+=item new_dbh
+
+ $dbh = C4::Context->new_dbh;
+
+Creates a new connection to the Koha database for the current context,
+and returns the database handle (a C<DBI::db> object).
+
+The handle is not saved anywhere: this method is strictly a
+convenience function; the point is that it knows which database to
+connect to so that the caller doesn't have to know.
+
+=cut
+
+#'
+sub new_dbh
+{
+ my $self = shift;
+
+ return &_new_dbh();
+}
+
+=item set_dbh
+
+ $my_dbh = C4::Connect->new_dbh;
+ C4::Connect->set_dbh($my_dbh);
+ ...
+ C4::Connect->restore_dbh;
+
+C<&set_dbh> and C<&restore_dbh> work in a manner analogous to
+C<&set_context> and C<&restore_context>.
+
+C<&set_dbh> saves the current database handle on a stack, then sets
+the current database handle to C<$my_dbh>.
+
+C<$my_dbh> is assumed to be a good database handle.
+
+=cut
+
+#'
+sub set_dbh
+{
+ my $self = shift;
+ my $new_dbh = shift;
+
+ # Save the current database handle on the handle stack.
+ # We assume that $new_dbh is all good: if the caller wants to
+ # screw himself by passing an invalid handle, that's fine by
+ # us.
+ push @{$context->{"dbh_stack"}}, $context->{"dbh"};
+ $context->{"dbh"} = $new_dbh;
+}
+
+=item restore_dbh
+
+ C4::Context->restore_dbh;
+
+Restores the database handle saved by an earlier call to
+C<C4::Context-E<gt>set_dbh>.
+
+=cut
+
+#'
+sub restore_dbh
+{
+ my $self = shift;
+
+ if ($#{$context->{"dbh_stack"}} < 0)
+ {
+ # Stack underflow
+ die "DBH stack underflow";
+ }
+
+ # Pop the old database handle and set it.
+ $context->{"dbh"} = pop @{$context->{"dbh_stack"}};
+
+ # FIXME - If it is determined that restore_context should
+ # return something, then this function should, too.
+}
+
+=item marcfromkohafield
+
+ $dbh = C4::Context->marcfromkohafield;
+
+Returns a hash with marcfromkohafield.
+
+This hash is cached for future use: if you call
+C<C4::Context-E<gt>marcfromkohafield> twice, you will get the same hash without real DB access
+
+=cut
+
+#'
+sub marcfromkohafield
+{
+ my $retval = {};
+
+ # If the hash already exists, return it.
+ return $context->{"marcfromkohafield"} if defined($context->{"marcfromkohafield"});
+
+ # No hash. Create one.
+ $context->{"marcfromkohafield"} = &_new_marcfromkohafield();
+
+ return $context->{"marcfromkohafield"};
+}
+
+
+# _new_marcfromkohafield
+# Internal helper function (not a method!).
+sub _new_marcfromkohafield
+{
+ my $dbh = C4::Context->dbh;
+ my $marcfromkohafield;
+ my $sth = $dbh->prepare("select kohafield,tagfield,tagsubfield,recordtype from koha_attr where tagfield is not null ");
+ $sth->execute;
+ while (my ($kohafield,$tagfield,$tagsubfield,$recordtype) = $sth->fetchrow) {
+ my $retval = {};
+ $marcfromkohafield->{$recordtype}->{$kohafield} = [$tagfield,$tagsubfield];
+ }
+
+ return $marcfromkohafield;
+}
+
+
+#item attrfromkohafield
+#To use as a hash of koha to z3950 attributes
+sub _new_attrfromkohafield
+{
+ my $dbh = C4::Context->dbh;
+ my $attrfromkohafield;
+ my $sth2 = $dbh->prepare("select kohafield,attr from koha_attr" );
+ $sth2->execute;
+ while (my ($kohafield,$attr) = $sth2->fetchrow) {
+ my $retval = {};
+ $attrfromkohafield->{$kohafield} = $attr;
+ }
+ return $attrfromkohafield;
+}
+sub attrfromkohafield
+{
+ my $retval = {};
+
+ # If the hash already exists, return it.
+ return $context->{"attrfromkohafield"} if defined($context->{"attrfromkohafield"});
+
+ # No hash. Create one.
+ $context->{"attrfromkohafield"} = &_new_attrfromkohafield();
+
+ return $context->{"attrfromkohafield"};
+}
+=item stopwords
+
+ $dbh = C4::Context->stopwords;
+
+Returns a hash with stopwords.
+
+This hash is cached for future use: if you call
+C<C4::Context-E<gt>stopwords> twice, you will get the same hash without real DB access
+
+=cut
+
+#'
+sub stopwords
+{
+ my $retval = {};
+
+ # If the hash already exists, return it.
+ return $context->{"stopwords"} if defined($context->{"stopwords"});
+
+ # No hash. Create one.
+ $context->{"stopwords"} = &_new_stopwords();
+
+ return $context->{"stopwords"};
+}
+
+# _new_stopwords
+# Internal helper function (not a method!). This creates a new
+# hash with stopwords
+sub _new_stopwords
+{
+ my $dbh = C4::Context->dbh;
+ my $stopwordlist;
+ my $sth = $dbh->prepare("select word from stopwords");
+ $sth->execute;
+ while (my $stopword = $sth->fetchrow_array) {
+ my $retval = {};
+ $stopwordlist->{$stopword} = uc($stopword);
+ }
+ $stopwordlist->{A} = "A" unless $stopwordlist;
+ return $stopwordlist;
+}
+
+=item userenv
+
+ C4::Context->userenv;
+
+Builds a hash for user environment variables.
+
+This hash shall be cached for future use: if you call
+C<C4::Context-E<gt>userenv> twice, you will get the same hash without real DB access
+
+set_userenv is called in Auth.pm
+
+=cut
+
+#'
+sub userenv
+{
+ my $var = $context->{"activeuser"};
+ return $context->{"userenv"}->{$var} if (defined $context->{"userenv"}->{$var});
+ return 0;
+ warn "NO CONTEXT for $var";
+}
+
+=item set_userenv
+
+ C4::Context->set_userenv($usernum, $userid, $usercnum, $userfirstname, $usersurname, $userbranch, $userflags, $emailaddress);
+
+Informs a hash for user environment variables.
+
+This hash shall be cached for future use: if you call
+C<C4::Context-E<gt>userenv> twice, you will get the same hash without real DB access
+
+set_userenv is called in Auth.pm
+
+=cut
+#'
+sub set_userenv{
+ my ($usernum, $userid, $usercnum, $userfirstname, $usersurname, $userbranch, $branchname, $userflags, $emailaddress,$branchprinter)= @_;
+ my $var=$context->{"activeuser"};
+ my $cell = {
+ "number" => $usernum,
+ "id" => $userid,
+ "cardnumber" => $usercnum,
+# "firstname" => $userfirstname,
+# "surname" => $usersurname,
+#possibly a law problem
+ "branch" => $userbranch,
+ "branchname" => $branchname,
+ "flags" => $userflags,
+ "emailaddress" => $emailaddress,
+ "branchprinter" => $branchprinter,
+ };
+ $context->{userenv}->{$var} = $cell;
+ return $cell;
+}
+
+=item _new_userenv
+
+ C4::Context->_new_userenv($session);
+
+Builds a hash for user environment variables.
+
+This hash shall be cached for future use: if you call
+C<C4::Context-E<gt>userenv> twice, you will get the same hash without real DB access
+
+_new_userenv is called in Auth.pm
+
+=cut
+
+#'
+sub _new_userenv
+{
+ shift;
+ my ($sessionID)= @_;
+ $context->{"activeuser"}=$sessionID;
+}
+
+=item _unset_userenv
+
+ C4::Context->_unset_userenv;
+
+Destroys the hash for activeuser user environment variables.
+
+=cut
+#'
+
+sub _unset_userenv
+{
+ my ($sessionID)= @_;
+ undef $context->{"activeuser"} if ($context->{"activeuser"} eq $sessionID);
+}
+
+
+
+1;
+__END__
+
+=back
+
+=head1 ENVIRONMENT
+
+=over 4
+
+=item C<KOHA_CONF>
+
+Specifies the configuration file to read.
+
+=back
+
+=head1 SEE ALSO
+
+DBI(3)
+
+=head1 AUTHOR
+
+Andrew Arensburger <arensb at ooblick dot com>
+
+=cut
+# $Log: Context.pm,v $
+# Revision 1.1.2.1 2007/03/10 01:35:34 tgarip1957
+# fresh files for rel_TG
+#
+# Revision 1.50 2006/11/06 21:01:43 tgarip1957
+# Bug fixing and complete removal of Date::Manip
+#
+# Revision 1.49 2006/10/20 01:20:56 tgarip1957
+# A new Date.pm to use for all date calculations. Mysql date calculations removed from Circ2.pm, all modules free of DateManip, a new get_today function to call in allscripts, and some bug cleaning in authorities.pm
+#
+# Revision 1.48 2006/10/01 21:48:54 tgarip1957
+# Field weighting applied to ranked searches. A new facets table in mysql db
+#
+# Revision 1.47 2006/09/27 19:53:52 tgarip1957
+# Finalizing main components. All koha modules are now working with the new XML API
+#
+# Revision 1.46 2006/09/06 16:21:03 tgarip1957
+# Clean up before final commits
+#
+# Revision 1.43 2006/08/10 12:49:37 toins
+# sync with dev_week.
+#
+# Revision 1.42 2006/07/04 14:36:51 toins
+# Head & rel_2_2 merged
+#
+# Revision 1.41 2006/05/20 14:36:09 tgarip1957
+# Typo error. Missing '>'
+#
+# Revision 1.40 2006/05/20 14:28:02 tgarip1957
+# Adding support to read zebra database name from config files
+#
+# Revision 1.39 2006/05/19 09:52:54 alaurin
+# committing new feature ip and printer management
+# adding two fields in branches table (branchip,branchprinter)
+#
+# branchip : if the library enter an ip or ip range any librarian that connect from computer in this ip range will be temporarly affected to the corresponding branch .
+#
+# branchprinter : the library can select a default printer for a branch
+#
+# Revision 1.38 2006/05/14 00:22:31 tgarip1957
+# Adding support for getting details of different zebra servers
+#
+# Revision 1.37 2006/05/13 19:51:39 tgarip1957
+# Now reads koha.xml rather than koha.conf.
+# koha.xml contains both the koha configuration and zebraserver configuration.
+# Zebra connection is modified to allow connection to authority zebra as well.
+# It will break head if koha.conf is not replaced with koha.xml
+#
+# Revision 1.36 2006/05/09 13:28:08 tipaul
+# adding the branchname and the librarian name in every page :
+# - modified userenv to add branchname
+# - modifier menus.inc to have the librarian name & userenv displayed on every page. they are in a librarian_information div.
+#
+# Revision 1.35 2006/04/13 08:40:11 plg
+# bug fixed: typo on Zconnauth name
+#
+# Revision 1.34 2006/04/10 21:40:23 tgarip1957
+# A new handler defined for zebra Zconnauth with read/write permission. Zconnauth should only be called in biblio.pm where write operations are. Use of this handler will break things unless koha.conf contains new variables:
+# zebradb=localhost
+# zebraport=<your port>
+# zebrauser=<username>
+# zebrapass=<password>
+#
+# The zebra.cfg file should read:
+# perm.anonymous:r
+# perm.username:rw
+# passw.c:<yourpasswordfile>
+#
+# Password file should be prepared with Apaches htpasswd utility in encrypted mode and should exist in a folder zebra.cfg can read
+#
+# Revision 1.33 2006/03/15 11:21:56 plg
+# bug fixed: utf-8 data where not displayed correctly in screens. Supposing
+# your data are truely utf-8 encoded in your database, they should be
+# correctly displayed. "set names 'UTF8'" on mysql connection (C4/Context.pm)
+# is mandatory and "binmode" to utf8 (C4/Interface/CGI/Output.pm) seemed to
+# converted data twice, so it was removed.
+#
+# Revision 1.32 2006/03/03 17:25:01 hdl
+# Bug fixing : a line missed a comment sign.
+#
+# Revision 1.31 2006/03/03 16:45:36 kados
+# Remove the search that tests the Zconn -- warning, still no fault
+# tollerance
+#
+# Revision 1.30 2006/02/22 00:56:59 kados
+# First go at a connection object for Zebra. You can now get a
+# connection object by doing:
+#
+# my $Zconn = C4::Context->Zconn;
+#
+# My initial tests indicate that as soon as your funcion ends
+# (ie, when you're done doing something) the connection will be
+# closed automatically. There may be some other way to make the
+# connection more stateful, I'm not sure...
+#
+# Local Variables:
+# tab-width: 4
+# End:
Index: Date-new.pm
===================================================================
RCS file: Date-new.pm
diff -N Date-new.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Date-new.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,232 @@
+#!/usr/bin/perl
+## written by T Garip 2006-10-10 tgarip at neu.edu.tr
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+# $Id: Date-new.pm,v 1.1.2.1 2007/03/10 01:35:34 tgarip1957 Exp $
+
+package C4::Date;
+
+use strict;
+use C4::Context;
+use Date::Calc qw(:all);
+
+require Exporter;
+
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
+
+$VERSION = do { my @v = '$Revision: 1.1.2.1 $' =~ /\d+/g; shift(@v) . "." . join( "_", map { sprintf "%03d", $_ } @v ); };
+
+ at ISA = qw(Exporter);
+
+ at EXPORT = qw(
+ &display_date_format
+ &format_date
+ &format_date_in_iso
+ &get_date_format_string_for_DHTMLcalendar
+ &DATE_diff &DATE_Add
+&get_today
+&DATE_subtract
+);
+
+sub get_date_format {
+
+ #Get the database handle
+ my $dbh = C4::Context->dbh;
+ return C4::Context->preference('dateformat');
+}
+
+sub display_date_format {
+ my $dateformat = get_date_format();
+
+ if ( $dateformat eq "us" ) {
+ return "mm/dd/yyyy";
+ }
+ elsif ( $dateformat eq "metric" ) {
+ return "dd/mm/yyyy";
+ }
+ elsif ( $dateformat eq "iso" ) {
+ return "yyyy-mm-dd";
+ }
+ else {
+ return
+"Invalid date format: $dateformat. Please change in system preferences";
+ }
+}
+
+sub get_date_format_string_for_DHTMLcalendar {
+ my $dateformat = get_date_format();
+
+ if ( $dateformat eq 'us' ) {
+ return '%m/%d/%Y';
+ }
+ elsif ( $dateformat eq 'metric' ) {
+ return '%d/%m/%Y';
+ }
+ elsif ( $dateformat eq "iso" ) {
+ return '%Y-%m-%d';
+ }
+ else {
+ return 'Invalid date format: '
+ . $dateformat . '.'
+ . ' Please change in system preferences';
+ }
+}
+
+sub format_date
+{
+ my $olddate = shift;
+ my $newdate;
+
+ if ( ! $olddate )
+ {
+ return "";
+ }
+
+# warn $olddate;
+# $olddate=~s#/|\.|-##g;
+ my ($year,$month,$day)=Parse_Date($olddate);
+ ($year,$month,$day)=split /-|\/|\.|:/,$olddate unless ($year && $month);
+# warn "$olddate annee $year mois $month jour $day";
+ if ($year>0 && $month>0){
+ my $dateformat = get_date_format();
+# $dateformat="metric" if (index(":",$olddate)>0);
+ if ( $dateformat eq "us" )
+ {
+ $newdate = sprintf("%02d/%02d/%04d",$month,$day,$year);
+ }
+ elsif ( $dateformat eq "metric" )
+ {
+ $newdate = sprintf("%02d/%02d/%04d",$day,$month,$year);
+ }
+ elsif ( $dateformat eq "iso" )
+ {
+ # Date_Init("DateFormat=iso");
+ $newdate = sprintf("%04d-%02d-%02d",$year,$month,$day);
+ }
+ else
+ {
+ return "Invalid date format: $dateformat. Please change in system preferences";
+ }
+# warn "newdate :$newdate";
+ }
+ return $newdate;
+}
+
+
+sub format_date_in_iso
+{
+ my $olddate = shift;
+ my $newdate;
+
+ if ( ! $olddate )
+ {
+ return "";
+ }
+ if (check_whether_iso($olddate)){
+ return $olddate;
+ } else {
+ my $dateformat = get_date_format();
+ my ($year,$month,$day);
+ my @date;
+ my $tmpolddate=$olddate;
+ $tmpolddate=~s#/|\.|-|\\##g;
+ $dateformat="metric" if (index(":",$olddate)>0);
+ if ( $dateformat eq "us" )
+ {
+ ($month,$day,$year)=split /-|\/|\.|:/,$olddate unless ($year && $month);
+ if ($month>0 && $day >0){
+ @date = Decode_Date_US($tmpolddate);
+ } else {
+ @date=($year, $month,$day)
+ }
+ }
+ elsif ( $dateformat eq "metric" )
+ {
+ ($day,$month,$year)=split /-|\/|\.|:/,$olddate unless ($year && $month);
+ if ($month>0 && $day >0){
+ @date = Decode_Date_EU($tmpolddate);
+ } else {
+ @date=($year, $month,$day)
+ }
+ }
+ elsif ( $dateformat eq "iso" )
+ {
+ ($year,$month,$day)=split /-|\/|\.|:/,$olddate unless ($year && $month);
+ if ($month>0 && $day >0){
+ @date=($year, $month,$day) if (check_date($year,$month,$day));
+ } else {
+ @date=($year, $month,$day)
+ }
+ }
+ else
+ {
+ return "9999-99-99";
+ }
+ $newdate = sprintf("%04d-%02d-%02d",$date[0],$date[1],$date[2]);
+ return $newdate;
+ }
+}
+
+sub check_whether_iso
+{
+ my $olddate = shift;
+ my @olddate= split /\-/,$olddate ;
+ return 1 if (length($olddate[0])==4 && length($olddate[1])<=2 && length($olddate[2])<=2);
+ return 0;
+}
+
+sub get_today{
+my ($year,$month,$day)=Today();
+return sprintf("%04d-%02d-%02d",$year,$month,$day);
+}
+
+###Utility functions for serials management
+sub DATE_diff {
+## returns 1 if date1>date2 0 if date1==date2 -1 if date1<date2
+my ($date1,$date2)=@_;
+my ($year1,$month1,$day1)=Parse_Date($date1);
+my ($year2,$month2,$day2)=Parse_Date($date2);
+return Delta_Days($year1,$month1,$day1, $year2,$month2,$day2)
+}
+
+sub DATE_Add {
+## $amount in days
+my ($date,$amount)=@_;
+my ($year,$month,$day)=Parse_Date($date);
+($year,$month,$day) = Add_Delta_Days($year,$month,$day, $amount);
+return sprintf("%04d-%02d-%02d",$year,$month,$day);
+}
+
+
+
+
+
+
+
+
+sub DATE_subtract{
+my ($date1,$date2)=@_;
+my ($year1,$month1,$day1)=Parse_Date($date1);
+my ($year2,$month2,$day2)=Parse_Date($date2);
+my $lower = Date_to_Days($year1,$month1,$day1);
+ my $upper = Date_to_Days($year2,$month2,$day2);
+
+return ($lower-$upper);
+}
+1;
+__END__
Index: Date.pm
===================================================================
RCS file: Date.pm
diff -N Date.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Date.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,218 @@
+#!/usr/bin/perl
+## written by T Garip 2006-10-10 tgarip at neu.edu.tr
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+# $Id: Date.pm,v 1.1.2.1 2007/03/10 01:35:34 tgarip1957 Exp $
+
+package C4::Date;
+
+use strict;
+use C4::Context;
+use DateTime;
+use DateTime::Format::ISO8601;
+use DateTime::Format::Strptime;
+use DateTime::Format::Duration;
+use POSIX qw(ceil floor);
+require Exporter;
+
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
+
+$VERSION = do { my @v = '$Revision: 1.1.2.1 $' =~ /\d+/g; shift(@v) . "." . join( "_", map { sprintf "%03d", $_ } @v ); };
+
+ at ISA = qw(Exporter);
+
+ at EXPORT = qw(
+ &display_date_format
+ &format_date
+ &format_date_in_iso
+ &get_date_format_string_for_DHTMLcalendar
+ &DATE_diff &DATE_Add
+&get_today &DATE_Add_Duration &DATE_obj &get_duration
+&DATE_subtract
+);
+
+sub get_date_format {
+
+ #Get the database handle
+ my $dbh = C4::Context->dbh;
+ return C4::Context->preference('dateformat');
+}
+
+sub display_date_format {
+ my $dateformat = get_date_format();
+
+ if ( $dateformat eq "us" ) {
+ return "mm/dd/yyyy";
+ }
+ elsif ( $dateformat eq "metric" ) {
+ return "dd/mm/yyyy";
+ }
+ elsif ( $dateformat eq "iso" ) {
+ return "yyyy-mm-dd";
+ }
+ else {
+ return
+"Invalid date format: $dateformat. Please change in system preferences";
+ }
+}
+
+sub get_date_format_string_for_DHTMLcalendar {
+ my $dateformat = get_date_format();
+
+ if ( $dateformat eq 'us' ) {
+ return '%m/%d/%Y';
+ }
+ elsif ( $dateformat eq 'metric' ) {
+ return '%d/%m/%Y';
+ }
+ elsif ( $dateformat eq "iso" ) {
+ return '%Y-%m-%d';
+ }
+ else {
+ return 'Invalid date format: '
+ . $dateformat . '.'
+ . ' Please change in system preferences';
+ }
+}
+
+sub format_date {
+ my $olddate = shift;
+ my $newdate;
+ if ( !$olddate || $olddate eq "0000-00-00" ) {
+ return "";
+ }
+ $olddate=~s/-//g;
+ $olddate=substr($olddate,0,8);
+ my $dateformat = get_date_format();
+eval{$newdate =DateTime::Format::ISO8601->parse_datetime($olddate);};
+if ($@ || !$newdate){
+##MARC21 tag 008 has this format YYMMDD
+my $parser = DateTime::Format::Strptime->new( pattern => '%y%m%d' );
+ $newdate =$parser->parse_datetime($olddate);
+}
+if (!$newdate){
+return ""; #### some script call format_date more than once --FIX scripts
+}
+
+ if ( $dateformat eq "us" ) {
+ return $newdate->mdy('/');
+
+ }
+ elsif ( $dateformat eq "metric" ) {
+ return $newdate->dmy('/');
+ }
+ elsif ( $dateformat eq "iso" ) {
+ return $newdate->ymd;
+ }
+ else {
+ return
+"Invalid date format: $dateformat. Please change in system preferences";
+ }
+
+}
+
+sub format_date_in_iso {
+ my $olddate = shift;
+ my $newdate;
+ my $parser;
+ if ( !$olddate || $olddate eq "0000-00-00" ) {
+ return "";
+ }
+
+$parser = DateTime::Format::Strptime->new( pattern => '%d/%m/%Y' );
+ $newdate =$parser->parse_datetime($olddate);
+if (!$newdate){
+$parser = DateTime::Format::Strptime->new( pattern => '%m/%d/%Y' );
+$newdate =$parser->parse_datetime($olddate);
+}
+if (!$newdate){
+ $parser = DateTime::Format::Strptime->new( pattern => '%Y-%m-%d' );
+$newdate =$parser->parse_datetime($olddate);
+}
+ if (!$newdate){
+ $parser = DateTime::Format::Strptime->new( pattern => '%y-%m-%d' );
+$newdate =$parser->parse_datetime($olddate);
+}
+
+ return $newdate->ymd if $newdate;
+}
+sub DATE_diff {
+## returns 1 if date1>date2 0 if date1==date2 -1 if date1<date2
+my ($date1,$date2)=@_;
+my $dt1=DateTime::Format::ISO8601->parse_datetime($date1);
+my $dt2=DateTime::Format::ISO8601->parse_datetime($date2);
+my $diff=DateTime->compare( $dt1, $dt2 );
+return $diff;
+}
+sub DATE_Add {
+## $amount in days
+my ($date,$amount)=@_;
+my $dt1=DateTime::Format::ISO8601->parse_datetime($date);
+$dt1->add( days=>$amount );
+return $dt1->ymd;
+}
+sub DATE_Add_Duration {
+## Similar as above but uses Duration object as amount --used heavily in serials
+my ($date,$amount)=@_;
+my $dt1=DateTime::Format::ISO8601->parse_datetime($date);
+$dt1->add_duration($amount) ;
+return $dt1->ymd;
+}
+sub get_today{
+my $dt=DateTime->now;
+$dt->add(hours=>2);
+return $dt->ymd;
+}
+
+sub DATE_obj{
+# only send iso dates to this
+my $date=shift;
+ my $parser = DateTime::Format::Strptime->new( pattern => '%Y-%m-%d' );
+ my $newdate =$parser->parse_datetime($date);
+return $newdate;
+}
+sub get_duration{
+my $period=shift;
+
+my $parse;
+if ($period=~/ays/){
+$parse="\%e days";
+}elsif ($period=~/week/){
+$parse="\%W weeks";
+}elsif ($period=~/year/){
+$parse="\%Y years";
+}elsif ($period=~/onth/){
+$parse="\%m months";
+}
+
+my $parser=DateTime::Format::Duration->new(pattern => $parse );
+ my $duration=$parser->parse_duration($period);
+
+return $duration;
+
+}
+sub DATE_subtract{
+my ($date1,$date2)=@_;
+my $dt1=DateTime::Format::ISO8601->parse_datetime($date1);
+my $dt2=DateTime::Format::ISO8601->parse_datetime($date2);
+my $dur=$dt2->subtract_datetime_absolute($dt1);## in seconds
+my $days=$dur->seconds/(60*60*24);
+return floor($days);
+}
+1;
+__END__
Index: Format.pm
===================================================================
RCS file: Format.pm
diff -N Format.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Format.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,232 @@
+package C4::Format;
+
+# $Id: Format.pm,v 1.1.2.1 2007/03/10 01:35:34 tgarip1957 Exp $
+
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+require Exporter;
+
+
+use vars qw($VERSION @ISA @EXPORT);
+
+# set the version for version checking
+$VERSION = 0.01;
+
+=head1 NAME
+
+C4::Format - Functions for pretty-printing strings and numbers
+
+=head1 SYNOPSIS
+
+ use C4::Format;
+
+=head1 DESCRIPTION
+
+These functions return pretty-printed versions of strings and numbers.
+
+=head1 FUNCTIONS
+
+=over 2
+
+=cut
+
+ at ISA = qw(Exporter);
+ at EXPORT = qw(&fmtstr &fmtdec);
+
+=item fmtstr
+
+ $str = &fmtstr($env, $string, $format);
+
+Returns C<$string>, padded with space to a given length.
+
+C<$format> is either C<Ln> or C<Rn>, where I<n> is a positive integer.
+C<$str> will be either left-padded or right-padded, respectively.
+
+C<&fmtstr> is almost equivalent to
+
+ sprintf("%-n.ns", $string);
+
+or
+
+ sprintf("%n.ns", $string);
+
+The only difference is that if I<n> is less than the length of
+C<$string>, then C<&fmtstr> will return the last I<n> characters of
+C<$string>, whereas C<sprintf> will return the first I<n> characters.
+
+C<$env> is ignored.
+
+=cut
+#'
+sub fmtstr {
+ # format (space pad) a string
+ # $fmt is Ln.. or Rn.. where n is the length
+ my ($env,$strg,$fmt)=@_;
+ my $align = substr($fmt,0,1);
+ my $lenst = substr($fmt,1,length($fmt)-1);
+ if ($align eq"R" ) {
+ $strg = substr((" "x$lenst).$strg,0-$lenst,$lenst);
+ } elsif ($align eq "C" ) {
+ $strg =
+ substr((" "x(($lenst/2)-(length($strg)/2))).$strg.(" "x$lenst),0,$lenst);
+ } else {
+ $strg = substr($strg.(" "x$lenst),0,$lenst);
+ }
+ return ($strg);
+}
+
+=item fmtdec
+
+ $str = &fmtdec($env, $number, $format)
+
+Returns a pretty-printed version of C<$number>.
+
+C<$format> specifies how to print the number. It is of the form
+
+ [$][,]n[m]
+
+where I<n> and I<m> are digits, specifying the number of digits to use
+before and after the decimal, respectively. Thus,
+
+ &fmtdec(undef, 123.456, "42")
+
+will return
+
+ " 123.45"
+
+If I<n> is smaller than the size of the integer part, only the last
+I<n> digits will be returned. If I<m> is greater than the number of
+digits after the decimal in C<$number>, the result will be
+right-padded with zeros.
+
+If C<$format> has a leading dollar sign, the number is assumed to be a
+monetary amount. C<$str> will have a dollar sign prepended to the
+value.
+
+If C<$format> has a comma after the optional dollar sign, the integer
+part will be split into three-digit groups separated by commas.
+
+C<$env> is effectively ignored.
+
+=cut
+#'
+# FIXME - This is all terribly provincial, not at all
+# internationalized. I'm pretty sure there's already something out
+# there that'll figure out the current locale, look up the local
+# currency symbol (and whether it goes on the left or right), figure
+# out how numbers are grouped (commas, periods, or what? And how many
+# digits per group?), and will print the whole thing prettily.
+# But I can't find it just now. Maybe POSIX::setlocale() or
+# perllocale(1) might help.
+# FIXME - Bug:
+# fmtdec(undef, 12345.6, ',82') prints " 345.60"
+# fmtdec(undef, 12345.6, '$,82') prints ".60"
+sub fmtdec {
+ # format a decimal
+ # $fmt is [$][,]n[m]
+ my ($env,$numb,$fmt)=@_;
+
+ # FIXME - Use $fmt =~ /^(\$)?(,)?(\d)(\d)?$/ instead of this mess of
+ # substr()s.
+
+ # See if there's a leading dollar sign.
+ my $curr = substr($fmt,0,1);
+ if ($curr eq "\$") {
+ $fmt = substr($fmt,1,length($fmt)-1);
+ };
+ # See if there's a leading comma
+ my $comma = substr($fmt,0,1);
+ if ($comma eq ",") {
+ $fmt = substr($fmt,1,length($fmt)-1);
+ };
+ # See whether one number was given, or two.
+ my $right;
+ my $left = substr($fmt,0,1);
+ if (length($fmt) == 1) {
+ $right = 0;
+ } else {
+ $right = substr($fmt,1,1);
+ }
+ # See if $numb is a floating-point number.
+ my $fnumb = "";
+ my $tempint = "";
+ my $tempdec = "";
+ # FIXME - Use
+ # $numb =~ /(\d+)\.(\d+)/;
+ # $tempint = $1 + 0;
+ # $tempdec = $2;
+ if (index($numb,".") == 0 ){
+ $tempint = 0;
+ $tempdec = substr($numb,1,length($numb)-1);
+ } else {
+ if (index($numb,".") > 0) {
+ my $decpl = index($numb,".");
+ $tempint = substr($numb,0,$decpl);
+ $tempdec = substr($numb,$decpl+1,length($numb)-1-$decpl);
+ } else {
+ $tempint = $numb;
+ $tempdec = 0;
+ }
+ # If a comma was specified, then comma-separate the integer part
+ # FIXME - From the Perl Cookbook (ISBN 1-56592-243-3), sec. 2.1.7:
+ # sub commify {
+ # my $test = reverse $_[0];
+ # $text =~ s/(\d\d\d)(?=\d)(?!\d*\.)/$1,/g;
+ # return scalar reverse $text;
+ # }
+ if ($comma eq ",") {
+ while (length($tempdec) > 3) {
+ $fnumb = ",".substr($tempint,-3,3).$fnumb;
+ substr($tempint,-3,3) = "";
+ }
+ $fnumb = substr($tempint,-3,3).$fnumb;
+ } else {
+ $fnumb = $tempint;
+ }
+ }
+ # If a dollar sign was specified, prepend a dollar sign and
+ # right-justify the number
+ if ($curr eq "\$") {
+ $fnumb = fmtstr($env,$curr.$fnumb,"R".$left+1);
+ } else {
+ if ($left==0) {
+ $fnumb = "";
+ } else {
+ $fnumb = fmtstr($env,$fnumb,"R".$left);
+ }
+ }
+ # Right-pad the decimal part to the given number of digits.
+ if ($right > 0) {
+ $tempdec .= "0"x$right;
+ $tempdec = substr($tempdec,0,$right);
+ $fnumb .= ".".$tempdec;
+ }
+ return $fnumb; # FIXME - Shouldn't return a list.
+}
+
+1;
+__END__
+
+=back
+
+=head1 AUTHOR
+
+Koha Developement team <info at koha.org>
+
+=cut
Index: Input.pm
===================================================================
RCS file: Input.pm
diff -N Input.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Input.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,220 @@
+package C4::Input; #assumes C4/Input
+
+
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+require Exporter;
+use C4::Context;
+
+use vars qw($VERSION @ISA @EXPORT);
+
+# set the version for version checking
+$VERSION = 0.01;
+
+=head1 NAME
+
+C4::Input - Miscellaneous sanity checks
+
+=head1 SYNOPSIS
+
+ use C4::Input;
+
+=head1 DESCRIPTION
+
+This module provides functions to see whether a given library card
+number or ISBN is valid.
+
+=head1 FUNCTIONS
+
+=over 2
+
+=cut
+
+ at ISA = qw(Exporter);
+ at EXPORT = qw(
+ &checkdigit &checkvalidisbn
+ &buildCGIsort
+);
+
+# FIXME - This is never used.
+#sub checkflds {
+# my ($env,$reqflds,$data) = @_;
+# my $numrflds = @$reqflds;
+# my @probarr;
+# my $i = 0;
+# while ($i < $numrflds) {
+# if ($data->{@$reqflds[$i]} eq "") {
+# push(@probarr, @$reqflds[$i]);
+# }
+# $i++
+# }
+# return (\@probarr);
+#}
+
+=item checkdigit
+
+ $valid = &checkdigit($env, $cardnumber $nounique);
+
+Takes a card number, computes its check digit, and compares it to the
+checkdigit at the end of C<$cardnumber>. Returns a true value iff
+C<$cardnumber> has a valid check digit.
+
+C<$env> is ignored.
+
+=cut
+#'
+sub checkdigit {
+
+ my ($env,$infl, $nounique) = @_;
+ $infl = uc $infl;
+
+
+ #Check to make sure the cardnumber is unique
+
+ #FIXME: We should make the error for a nonunique cardnumber
+ #different from the one where the checkdigit on the number is
+ #not correct
+
+ unless ( $nounique )
+ {
+ my $dbh=C4::Context->dbh;
+ my $query=qq{SELECT * FROM borrowers WHERE cardnumber=?};
+ my $sth=$dbh->prepare($query);
+ $sth->execute($infl);
+ my %results = $sth->fetchrow_hashref();
+ if ( $sth->rows != 0 )
+ {
+ return 0;
+ }
+ }
+ if (C4::Context->preference("checkdigit") eq "none") {
+ return 1;
+ }
+
+ my @weightings = (8,4,6,3,5,2,1);
+ my $sum;
+ my $i = 1;
+ my $valid = 0;
+
+ foreach $i (1..7) {
+ my $temp1 = $weightings[$i-1];
+ my $temp2 = substr($infl,$i,1);
+ $sum += $temp1 * $temp2;
+ }
+ my $rem = ($sum%11);
+ if ($rem == 10) {
+ $rem = "X";
+ }
+ if ($rem eq substr($infl,8,1)) {
+ $valid = 1;
+ }
+ return $valid;
+} # sub checkdigit
+
+=item checkvalidisbn
+
+ $valid = &checkvalidisbn($isbn);
+
+Returns a true value iff C<$isbn> is a valid ISBN: it must be ten
+digits long (counting "X" as a digit), and must have a valid check
+digit at the end.
+
+=cut
+#'
+#--------------------------------------
+# Determine if a number is a valid ISBN number, according to length
+# of 10 digits and valid checksum
+sub checkvalidisbn {
+ use strict;
+ my ($q)=@_ ; # Input: ISBN number
+
+ my $isbngood = 0; # Return: true or false
+
+ $q=~s/x$/X/g; # upshift lower case X
+ $q=~s/[^X\d]//g;
+ $q=~s/X.//g;
+
+ #return 0 if $q is not ten digits long
+ if (length($q)!=10) {
+ return 0;
+ }
+
+ #If we get to here, length($q) must be 10
+ my $checksum=substr($q,9,1);
+ my $isbn=substr($q,0,9);
+ my $i;
+ my $c=0;
+ for ($i=0; $i<9; $i++) {
+ my $digit=substr($q,$i,1);
+ $c+=$digit*(10-$i);
+ }
+ $c %= 11;
+ ($c==10) && ($c='X');
+ $isbngood = $c eq $checksum;
+ return $isbngood;
+
+} # sub checkvalidisbn
+
+=item buildCGISort
+
+ $CGIScrollingList = &BuildCGISort($name string, $input_name string);
+
+Returns the scrolling list with name $input_name, built on authorised Values named $name.
+Returns NULL if no authorised values found
+
+=cut
+sub buildCGIsort {
+ use strict;
+ my ($name,$input_name,$data) = @_;
+ my $dbh=C4::Context->dbh;
+ my $query=qq{SELECT * FROM authorised_values WHERE category=? order by lib};
+ my $sth=$dbh->prepare($query);
+ $sth->execute($name);
+ my $CGISort;
+ if ($sth->rows>0){
+ my @values;
+ my %labels;
+ for (my $i =0;$i<=$sth->rows;$i++){
+ my $results = $sth->fetchrow_hashref;
+ push @values, $results->{authorised_value};
+ $labels{$results->{authorised_value}}=$results->{lib};
+ }
+ $CGISort= CGI::scrolling_list(
+ -name => $input_name,
+ -values => \@values,
+ -labels => \%labels,
+ -default=> $data,
+ -size => 1,
+ -multiple => 0);
+ }
+ $sth->finish;
+ return $CGISort;
+}
+END { } # module clean-up code here (global destructor)
+
+1;
+__END__
+
+=back
+
+=head1 AUTHOR
+
+Koha Developement team <info at koha.org>
+
+=cut
Index: Koha.pm
===================================================================
RCS file: Koha.pm
diff -N Koha.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Koha.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,961 @@
+package C4::Koha;
+
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+# $Id: Koha.pm,v 1.1.2.1 2007/03/10 01:35:34 tgarip1957 Exp $
+
+use strict;
+require Exporter;
+use C4::Context;
+use C4::Biblio;
+use CGI;
+use vars qw($VERSION @ISA @EXPORT);
+
+$VERSION = do { my @v = '$Revision: 1.1.2.1 $' =~ /\d+/g; shift(@v) . "." . join("_", map {sprintf "%03d", $_ } @v); };
+
+=head1 NAME
+
+C4::Koha - Perl Module containing convenience functions for Koha scripts
+
+=head1 SYNOPSIS
+
+ use C4::Koha;
+
+
+=head1 DESCRIPTION
+
+Koha.pm provides many functions for Koha scripts.
+
+=head1 FUNCTIONS
+
+=over 2
+
+=cut
+
+ at ISA = qw(Exporter);
+ at EXPORT = qw(
+ &subfield_is_koha_internal_p
+ &GetBranches &getbranch &getbranchdetail
+ &getprinters &getprinter
+ &GetItemTypes &getitemtypeinfo &ItemType
+ get_itemtypeinfos_of
+ &getframeworks &getframeworkinfo
+ &getauthtypes &getauthtype
+ &getallthemes &getalllanguages
+ &GetallBranches &getletters
+ &getbranchname
+ getnbpages
+ getitemtypeimagedir
+ getitemtypeimagesrc
+ getitemtypeimagesrcfromurl
+ &getcities
+ &getroadtypes
+ get_branchinfos_of
+ get_notforloan_label_of
+ get_infos_of
+ &getFacets
+
+ $DEBUG);
+
+use vars qw();
+
+my $DEBUG = 0;
+
+# FIXME.. this should be moved to a MARC-specific module
+sub subfield_is_koha_internal_p {
+ my($subfield) = @_;
+
+ # We could match on 'lib' and 'tab' (and 'mandatory', & more to come!)
+ # But real MARC subfields are always single-character
+ # so it really is safer just to check the length
+
+ return length $subfield != 1;
+}
+
+=head2 GetBranches
+
+ $branches = &GetBranches();
+ returns informations about branches.
+ Create a branch selector with the following code
+ Is branchIndependant sensitive
+ When IndependantBranches is set AND user is not superlibrarian, displays only user's branch
+
+=head3 in PERL SCRIPT
+
+my $branches = GetBranches;
+my @branchloop;
+foreach my $thisbranch (sort keys %$branches) {
+ my $selected = 1 if $thisbranch eq $branch;
+ my %row =(value => $thisbranch,
+ selected => $selected,
+ branchname => $branches->{$thisbranch}->{'branchname'},
+ );
+ push @branchloop, \%row;
+}
+
+
+=head3 in TEMPLATE
+ <select name="branch">
+ <option value="">Default</option>
+ <!-- TMPL_LOOP name="branchloop" -->
+ <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="branchname" --></option>
+ <!-- /TMPL_LOOP -->
+ </select>
+
+=cut
+
+sub GetBranches {
+# returns a reference to a hash of references to branches...
+ my ($type) = @_;
+ my %branches;
+ my $branch;
+ my $dbh = C4::Context->dbh;
+ my $sth;
+ if (C4::Context->preference("IndependantBranches") && (C4::Context->userenv->{flags}!=1)){
+ my $strsth ="Select * from branches ";
+ $strsth.= " WHERE branchcode = ".$dbh->quote(C4::Context->userenv->{branch});
+ $strsth.= " order by branchname";
+ $sth=$dbh->prepare($strsth);
+ } else {
+ $sth = $dbh->prepare("Select * from branches order by branchname");
+ }
+ $sth->execute;
+ while ($branch=$sth->fetchrow_hashref) {
+ my $nsth = $dbh->prepare("select categorycode from branchrelations where branchcode = ?");
+ if ($type){
+ $nsth = $dbh->prepare("select categorycode from branchrelations where branchcode = ? and categorycode = ?");
+ $nsth->execute($branch->{'branchcode'},$type);
+ } else {
+ $nsth = $dbh->prepare("select categorycode from branchrelations where branchcode = ? ");
+
+ $nsth->execute($branch->{'branchcode'});
+ }
+ while (my ($cat) = $nsth->fetchrow_array) {
+ # FIXME - This seems wrong. It ought to be
+ # $branch->{categorycodes}{$cat} = 1;
+ # otherwise, there's a namespace collision if there's a
+ # category with the same name as a field in the 'branches'
+ # table (i.e., don't create a category called "issuing").
+ # In addition, the current structure doesn't really allow
+ # you to list the categories that a branch belongs to:
+ # you'd have to list keys %$branch, and remove those keys
+ # that aren't fields in the "branches" table.
+ $branch->{$cat} = 1;
+ }
+ $branches{$branch->{'branchcode'}}=$branch;
+}
+ return (\%branches);
+}
+
+sub getbranchname {
+ my ($branchcode)=@_;
+ my $dbh = C4::Context->dbh;
+ my $sth;
+ $sth = $dbh->prepare("Select branchname from branches where branchcode=?");
+ $sth->execute($branchcode);
+ my $branchname = $sth->fetchrow_array;
+ $sth->finish;
+
+ return($branchname);
+}
+
+=head2 getallbranches
+
+ @branches = &GetallBranches();
+ returns informations about ALL branches.
+ Create a branch selector with the following code
+ IndependantBranches Insensitive...
+
+
+=cut
+
+
+sub GetallBranches {
+# returns an array to ALL branches...
+ my @branches;
+ my $dbh = C4::Context->dbh;
+ my $sth;
+ $sth = $dbh->prepare("Select * from branches order by branchname");
+ $sth->execute;
+ while (my $branch=$sth->fetchrow_hashref) {
+ push @branches,$branch;
+ }
+ return (@branches);
+}
+
+=head2 getletters
+
+ $letters = &getletters($category);
+ returns informations about letters.
+ if needed, $category filters for letters given category
+ Create a letter selector with the following code
+
+=head3 in PERL SCRIPT
+
+my $letters = getletters($cat);
+my @letterloop;
+foreach my $thisletter (keys %$letters) {
+ my $selected = 1 if $thisletter eq $letter;
+ my %row =(value => $thisletter,
+ selected => $selected,
+ lettername => $letters->{$thisletter},
+ );
+ push @letterloop, \%row;
+}
+
+
+=head3 in TEMPLATE
+ <select name="letter">
+ <option value="">Default</option>
+ <!-- TMPL_LOOP name="letterloop" -->
+ <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="lettername" --></option>
+ <!-- /TMPL_LOOP -->
+ </select>
+
+=cut
+
+sub getletters {
+# returns a reference to a hash of references to ALL letters...
+ my $cat =@_;
+ my %letters;
+ my $dbh = C4::Context->dbh;
+ my $sth;
+ if ($cat ne ""){
+ $sth = $dbh->prepare("Select * from letter where module = \'".$cat."\' order by name");
+ } else {
+ $sth = $dbh->prepare("Select * from letter order by name");
+ }
+ $sth->execute;
+ my $count;
+ while (my $letter=$sth->fetchrow_hashref) {
+ $letters{$letter->{'code'}}=$letter->{'name'};
+ $count++;
+ }
+ return ($count,\%letters);
+}
+
+=head2 GetItemTypes
+
+ $itemtypes = &GetItemTypes();
+
+Returns information about existing itemtypes.
+
+build a HTML select with the following code :
+
+=head3 in PERL SCRIPT
+
+my $itemtypes = GetItemTypes;
+my @itemtypesloop;
+foreach my $thisitemtype (sort keys %$itemtypes) {
+ my $selected = 1 if $thisitemtype eq $itemtype;
+ my %row =(value => $thisitemtype,
+ selected => $selected,
+ description => $itemtypes->{$thisitemtype}->{'description'},
+ );
+ push @itemtypesloop, \%row;
+}
+$template->param(itemtypeloop => \@itemtypesloop);
+
+=head3 in TEMPLATE
+
+<form action='<!-- TMPL_VAR name="script_name" -->' method=post>
+ <select name="itemtype">
+ <option value="">Default</option>
+ <!-- TMPL_LOOP name="itemtypeloop" -->
+ <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="description" --></option>
+ <!-- /TMPL_LOOP -->
+ </select>
+ <input type=text name=searchfield value="<!-- TMPL_VAR name="searchfield" -->">
+ <input type="submit" value="OK" class="button">
+</form>
+
+
+=cut
+
+sub GetItemTypes {
+# returns a reference to a hash of references to branches...
+ my %itemtypes;
+ my $dbh = C4::Context->dbh;
+ my $query = qq|
+ SELECT *
+ FROM itemtypes
+ |;
+ my $sth=$dbh->prepare($query);
+ $sth->execute;
+ while (my $IT=$sth->fetchrow_hashref) {
+ $itemtypes{$IT->{'itemtype'}}=$IT;
+ }
+ return (\%itemtypes);
+}
+
+# FIXME this function is better and should replace GetItemTypes everywhere
+sub get_itemtypeinfos_of {
+ my @itemtypes = @_;
+
+ my $query = '
+SELECT itemtype,
+ description,
+ notforloan
+ FROM itemtypes
+ WHERE itemtype IN ('.join(',', map({"'".$_."'"} @itemtypes)).')
+';
+
+ return get_infos_of($query, 'itemtype');
+}
+
+sub ItemType {
+ my ($type)=@_;
+ my $dbh = C4::Context->dbh;
+ my $sth=$dbh->prepare("select description from itemtypes where itemtype=?");
+ $sth->execute($type);
+ my $dat=$sth->fetchrow_hashref;
+ $sth->finish;
+ return ($dat->{'description'});
+}
+=head2 getauthtypes
+
+ $authtypes = &getauthtypes();
+
+Returns information about existing authtypes.
+
+build a HTML select with the following code :
+
+=head3 in PERL SCRIPT
+
+my $authtypes = getauthtypes;
+my @authtypesloop;
+foreach my $thisauthtype (keys %$authtypes) {
+ my $selected = 1 if $thisauthtype eq $authtype;
+ my %row =(value => $thisauthtype,
+ selected => $selected,
+ authtypetext => $authtypes->{$thisauthtype}->{'authtypetext'},
+ );
+ push @authtypesloop, \%row;
+}
+$template->param(itemtypeloop => \@itemtypesloop);
+
+=head3 in TEMPLATE
+
+<form action='<!-- TMPL_VAR name="script_name" -->' method=post>
+ <select name="authtype">
+ <!-- TMPL_LOOP name="authtypeloop" -->
+ <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="authtypetext" --></option>
+ <!-- /TMPL_LOOP -->
+ </select>
+ <input type=text name=searchfield value="<!-- TMPL_VAR name="searchfield" -->">
+ <input type="submit" value="OK" class="button">
+</form>
+
+
+=cut
+
+sub getauthtypes {
+# returns a reference to a hash of references to authtypes...
+ my %authtypes;
+ my $dbh = C4::Context->dbh;
+ my $sth=$dbh->prepare("select * from auth_types order by authtypetext");
+ $sth->execute;
+ while (my $IT=$sth->fetchrow_hashref) {
+ $authtypes{$IT->{'authtypecode'}}=$IT;
+ }
+ return (\%authtypes);
+}
+
+sub getauthtype {
+ my ($authtypecode) = @_;
+# returns a reference to a hash of references to authtypes...
+ my %authtypes;
+ my $dbh = C4::Context->dbh;
+ my $sth=$dbh->prepare("select * from auth_types where authtypecode=?");
+ $sth->execute($authtypecode);
+ my $res=$sth->fetchrow_hashref;
+ return $res;
+}
+
+=head2 getframework
+
+ $frameworks = &getframework();
+
+Returns information about existing frameworks
+
+build a HTML select with the following code :
+
+=head3 in PERL SCRIPT
+
+my $frameworks = frameworks();
+my @frameworkloop;
+foreach my $thisframework (keys %$frameworks) {
+ my $selected = 1 if $thisframework eq $frameworkcode;
+ my %row =(value => $thisframework,
+ selected => $selected,
+ description => $frameworks->{$thisframework}->{'frameworktext'},
+ );
+ push @frameworksloop, \%row;
+}
+$template->param(frameworkloop => \@frameworksloop);
+
+=head3 in TEMPLATE
+
+<form action='<!-- TMPL_VAR name="script_name" -->' method=post>
+ <select name="frameworkcode">
+ <option value="">Default</option>
+ <!-- TMPL_LOOP name="frameworkloop" -->
+ <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="frameworktext" --></option>
+ <!-- /TMPL_LOOP -->
+ </select>
+ <input type=text name=searchfield value="<!-- TMPL_VAR name="searchfield" -->">
+ <input type="submit" value="OK" class="button">
+</form>
+
+
+=cut
+
+sub getframeworks {
+# returns a reference to a hash of references to branches...
+ my %itemtypes;
+ my $dbh = C4::Context->dbh;
+ my $sth=$dbh->prepare("select * from biblios_framework");
+ $sth->execute;
+ while (my $IT=$sth->fetchrow_hashref) {
+ $itemtypes{$IT->{'frameworkcode'}}=$IT;
+ }
+ return (\%itemtypes);
+}
+=head2 getframeworkinfo
+
+ $frameworkinfo = &getframeworkinfo($frameworkcode);
+
+Returns information about an frameworkcode.
+
+=cut
+
+sub getframeworkinfo {
+ my ($frameworkcode) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth=$dbh->prepare("select * from biblios_framework where frameworkcode=?");
+ $sth->execute($frameworkcode);
+ my $res = $sth->fetchrow_hashref;
+ return $res;
+}
+
+
+=head2 getitemtypeinfo
+
+ $itemtype = &getitemtype($itemtype);
+
+Returns information about an itemtype.
+
+=cut
+
+sub getitemtypeinfo {
+ my ($itemtype) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth=$dbh->prepare("select * from itemtypes where itemtype=?");
+ $sth->execute($itemtype);
+ my $res = $sth->fetchrow_hashref;
+
+ $res->{imageurl} = getitemtypeimagesrcfromurl($res->{imageurl});
+
+ return $res;
+}
+
+sub getitemtypeimagesrcfromurl {
+ my ($imageurl) = @_;
+
+ if (defined $imageurl and $imageurl !~ m/^http/) {
+ $imageurl =
+ getitemtypeimagesrc()
+ .'/'.$imageurl
+ ;
+ }
+
+ return $imageurl;
+}
+
+sub getitemtypeimagedir {
+ return
+ C4::Context->intrahtdocs
+ .'/'.C4::Context->preference('template')
+ .'/itemtypeimg'
+ ;
+}
+
+sub getitemtypeimagesrc {
+ return
+ '/intranet-tmpl'
+ .'/'.C4::Context->preference('template')
+ .'/itemtypeimg'
+ ;
+}
+
+=head2 getprinters
+
+ $printers = &getprinters($env);
+ @queues = keys %$printers;
+
+Returns information about existing printer queues.
+
+C<$env> is ignored.
+
+C<$printers> is a reference-to-hash whose keys are the print queues
+defined in the printers table of the Koha database. The values are
+references-to-hash, whose keys are the fields in the printers table.
+
+=cut
+
+sub getprinters {
+ my ($env) = @_;
+ my %printers;
+ my $dbh = C4::Context->dbh;
+ my $sth=$dbh->prepare("select * from printers");
+ $sth->execute;
+ while (my $printer=$sth->fetchrow_hashref) {
+ $printers{$printer->{'printqueue'}}=$printer;
+ }
+ return (\%printers);
+}
+
+sub getbranch {
+ my($query, $branches) = @_; # get branch for this query from branches
+ my $branch = $query->param('branch');
+ ($branch) || ($branch = $query->cookie('branch'));
+ ($branches->{$branch}) || ($branch=(keys %$branches)[0]);
+ return $branch;
+}
+
+=item getbranchdetail
+
+ $branchname = &getbranchdetail($branchcode);
+
+Given the branch code, the function returns the corresponding
+branch name for a comprehensive information display
+
+=cut
+
+sub getbranchdetail
+{
+ my ($branchcode) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("SELECT * FROM branches WHERE branchcode = ?");
+ $sth->execute($branchcode);
+ my $branchname = $sth->fetchrow_hashref();
+ $sth->finish();
+ return $branchname;
+} # sub getbranchname
+
+
+sub getprinter {
+ my($query, $printers) = @_; # get printer for this query from printers
+ my $printer = $query->param('printer');
+ ($printer) || ($printer = $query->cookie('printer')) || ($printer='');
+ ($printers->{$printer}) || ($printer = (keys %$printers)[0]);
+ return $printer;
+}
+
+=item getalllanguages
+
+ (@languages) = &getalllanguages($type);
+ (@languages) = &getalllanguages($type,$theme);
+
+Returns an array of all available languages.
+
+=cut
+
+sub getalllanguages {
+ my $type=shift;
+ my $theme=shift;
+ my $htdocs;
+ my @languages;
+ if ($type eq 'opac') {
+ $htdocs=C4::Context->config('opachtdocs');
+ if ($theme and -d "$htdocs/$theme") {
+ opendir D, "$htdocs/$theme";
+ foreach my $language (readdir D) {
+ next if $language=~/^\./;
+ next if $language eq 'all';
+ next if $language=~ /png$/;
+ next if $language=~ /css$/;
+ next if $language=~ /images$/;
+ next if $language=~ /CVS$/;
+ next if $language=~ /itemtypeimg$/;
+ next if $language=~ /\.txt$/i; #Don't read the readme.txt !
+ push @languages, $language;
+ }
+ return sort @languages;
+ } else {
+ my $lang;
+ foreach my $theme (getallthemes('opac')) {
+ opendir D, "$htdocs/$theme";
+ foreach my $language (readdir D) {
+ next if $language=~/^\./;
+ next if $language eq 'all';
+ next if $language=~ /png$/;
+ next if $language=~ /css$/;
+ next if $language=~ /images$/;
+ next if $language=~ /CVS$/;
+ next if $language=~ /itemtypeimg$/;
+ next if $language=~ /\.txt$/i; #Don't read the readme.txt !
+ $lang->{$language}=1;
+ }
+ }
+ @languages=keys %$lang;
+ return sort @languages;
+ }
+ } elsif ($type eq 'intranet') {
+ $htdocs=C4::Context->config('intrahtdocs');
+ if ($theme and -d "$htdocs/$theme") {
+ opendir D, "$htdocs/$theme";
+ foreach my $language (readdir D) {
+ next if $language=~/^\./;
+ next if $language eq 'all';
+ next if $language=~ /png$/;
+ next if $language=~ /css$/;
+ next if $language=~ /images$/;
+ next if $language=~ /CVS$/;
+ next if $language=~ /itemtypeimg$/;
+ next if $language=~ /\.txt$/i; #Don't read the readme.txt !
+ push @languages, $language;
+ }
+ return sort @languages;
+ } else {
+ my $lang;
+ foreach my $theme (getallthemes('opac')) {
+ opendir D, "$htdocs/$theme";
+ foreach my $language (readdir D) {
+ next if $language=~/^\./;
+ next if $language eq 'all';
+ next if $language=~ /png$/;
+ next if $language=~ /css$/;
+ next if $language=~ /images$/;
+ next if $language=~ /CVS$/;
+ next if $language=~ /itemtypeimg$/;
+ next if $language=~ /\.txt$/i; #Don't read the readme.txt !
+ $lang->{$language}=1;
+ }
+ }
+ @languages=keys %$lang;
+ return sort @languages;
+ }
+ } else {
+ my $lang;
+ my $htdocs=C4::Context->config('intrahtdocs');
+ foreach my $theme (getallthemes('intranet')) {
+ opendir D, "$htdocs/$theme";
+ foreach my $language (readdir D) {
+ next if $language=~/^\./;
+ next if $language eq 'all';
+ next if $language=~ /png$/;
+ next if $language=~ /css$/;
+ next if $language=~ /images$/;
+ next if $language=~ /CVS$/;
+ next if $language=~ /itemtypeimg$/;
+ next if $language=~ /\.txt$/i; #Don't read the readme.txt !
+ $lang->{$language}=1;
+ }
+ }
+ $htdocs=C4::Context->config('opachtdocs');
+ foreach my $theme (getallthemes('opac')) {
+ opendir D, "$htdocs/$theme";
+ foreach my $language (readdir D) {
+ next if $language=~/^\./;
+ next if $language eq 'all';
+ next if $language=~ /png$/;
+ next if $language=~ /css$/;
+ next if $language=~ /images$/;
+ next if $language=~ /CVS$/;
+ next if $language=~ /itemtypeimg$/;
+ next if $language=~ /\.txt$/i; #Don't read the readme.txt !
+ $lang->{$language}=1;
+ }
+ }
+ @languages=keys %$lang;
+ return sort @languages;
+ }
+}
+
+=item getallthemes
+
+ (@themes) = &getallthemes('opac');
+ (@themes) = &getallthemes('intranet');
+
+Returns an array of all available themes.
+
+=cut
+
+sub getallthemes {
+ my $type=shift;
+ my $htdocs;
+ my @themes;
+ if ($type eq 'intranet') {
+ $htdocs=C4::Context->config('intrahtdocs');
+ } else {
+ $htdocs=C4::Context->config('opachtdocs');
+ }
+ opendir D, "$htdocs";
+ my @dirlist=readdir D;
+ foreach my $directory (@dirlist) {
+ -d "$htdocs/$directory/en" and push @themes, $directory;
+ }
+ return @themes;
+}
+
+=item getnbpages
+
+Returns the number of pages to display in a pagination bar, given the number
+of items and the number of items per page.
+
+=cut
+
+sub getnbpages {
+ my ($nb_items, $nb_items_per_page) = @_;
+
+ return int(($nb_items - 1) / $nb_items_per_page) + 1;
+}
+
+
+=head2 getcities (OUEST-PROVENCE)
+
+ ($id_cityarrayref, $city_hashref) = &getcities();
+
+Looks up the different city and zip in the database. Returns two
+elements: a reference-to-array, which lists the zip city
+codes, and a reference-to-hash, which maps the name of the city.
+WHERE =>OUEST PROVENCE OR EXTERIEUR
+
+=cut
+sub getcities {
+ #my ($type_city) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth=$dbh->prepare("Select cityid,city_name from cities order by cityid ");
+ #$sth->execute($type_city);
+ $sth->execute();
+ my %city;
+ my @id;
+# insert empty value to create a empty choice in cgi popup
+
+while (my $data=$sth->fetchrow_hashref){
+
+ push @id,$data->{'cityid'};
+ $city{$data->{'cityid'}}=$data->{'city_name'};
+ }
+
+ #test to know if the table contain some records if no the function return nothing
+ my $id=@id;
+ $sth->finish;
+ if ($id eq 0)
+ {
+ return();
+ }
+ else{
+ unshift (@id ,"");
+ return(\@id,\%city);
+ }
+}
+
+
+=head2 getroadtypes (OUEST-PROVENCE)
+
+ ($idroadtypearrayref, $roadttype_hashref) = &getroadtypes();
+
+Looks up the different road type . Returns two
+elements: a reference-to-array, which lists the id_roadtype
+codes, and a reference-to-hash, which maps the road type of the road .
+
+
+=cut
+sub getroadtypes {
+ my $dbh = C4::Context->dbh;
+ my $sth=$dbh->prepare("Select roadtypeid,road_type from roadtype order by road_type ");
+ $sth->execute();
+ my %roadtype;
+ my @id;
+# insert empty value to create a empty choice in cgi popup
+while (my $data=$sth->fetchrow_hashref){
+ push @id,$data->{'roadtypeid'};
+ $roadtype{$data->{'roadtypeid'}}=$data->{'road_type'};
+ }
+ #test to know if the table contain some records if no the function return nothing
+ my $id=@id;
+ $sth->finish;
+ if ($id eq 0)
+ {
+ return();
+ }
+ else{
+ unshift (@id ,"");
+ return(\@id,\%roadtype);
+ }
+}
+
+=head2 get_branchinfos_of
+
+ my $branchinfos_of = get_branchinfos_of(@branchcodes);
+
+Associates a list of branchcodes to the information of the branch, taken in
+branches table.
+
+Returns a href where keys are branchcodes and values are href where keys are
+branch information key.
+
+ print 'branchname is ', $branchinfos_of->{$code}->{branchname};
+
+=cut
+sub get_branchinfos_of {
+ my @branchcodes = @_;
+
+ my $query = '
+SELECT branchcode,
+ branchname
+ FROM branches
+ WHERE branchcode IN ('.join(',', map({"'".$_."'"} @branchcodes)).')
+';
+ return get_infos_of($query, 'branchcode');
+}
+
+=head2 get_notforloan_label_of
+
+ my $notforloan_label_of = get_notforloan_label_of();
+
+Each authorised value of notforloan (information available in items and
+itemtypes) is link to a single label.
+
+Returns a href where keys are authorised values and values are corresponding
+labels.
+
+ foreach my $authorised_value (keys %{$notforloan_label_of}) {
+ printf(
+ "authorised_value: %s => %s\n",
+ $authorised_value,
+ $notforloan_label_of->{$authorised_value}
+ );
+ }
+
+=cut
+sub get_notforloan_label_of {
+ my $dbh = C4::Context->dbh;
+my($tagfield,$tagsubfield)=MARCfind_marc_from_kohafield("notforloan","holdings");
+ my $query = '
+SELECT authorised_value
+ FROM holdings_subfield_structure
+ WHERE tagfield =$tagfield and tagsubfield=$tagsubfield
+ LIMIT 0, 1
+';
+ my $sth = $dbh->prepare($query);
+ $sth->execute();
+ my ($statuscode) = $sth->fetchrow_array();
+
+ $query = '
+SELECT lib,
+ authorised_value
+ FROM authorised_values
+ WHERE category = ?
+';
+ $sth = $dbh->prepare($query);
+ $sth->execute($statuscode);
+ my %notforloan_label_of;
+ while (my $row = $sth->fetchrow_hashref) {
+ $notforloan_label_of{ $row->{authorised_value} } = $row->{lib};
+ }
+ $sth->finish;
+
+ return \%notforloan_label_of;
+}
+
+=head2 get_infos_of
+
+Return a href where a key is associated to a href. You give a query, the
+name of the key among the fields returned by the query. If you also give as
+third argument the name of the value, the function returns a href of scalar.
+
+ my $query = '
+SELECT itemnumber,
+ notforloan,
+ barcode
+ FROM items
+';
+
+ # generic href of any information on the item, href of href.
+ my $iteminfos_of = get_infos_of($query, 'itemnumber');
+ print $iteminfos_of->{$itemnumber}{barcode};
+
+ # specific information, href of scalar
+ my $barcode_of_item = get_infos_of($query, 'itemnumber', 'barcode');
+ print $barcode_of_item->{$itemnumber};
+
+=cut
+sub get_infos_of {
+ my ($query, $key_name, $value_name) = @_;
+
+ my $dbh = C4::Context->dbh;
+
+ my $sth = $dbh->prepare($query);
+ $sth->execute();
+
+ my %infos_of;
+ while (my $row = $sth->fetchrow_hashref) {
+ if (defined $value_name) {
+ $infos_of{ $row->{$key_name} } = $row->{$value_name};
+ }
+ else {
+ $infos_of{ $row->{$key_name} } = $row;
+ }
+ }
+ $sth->finish;
+
+ return \%infos_of;
+}
+sub getFacets {
+###Subfields is an array as well although MARC21 has them all in "a" in case UNIMARC has differing subfields
+my $dbh=C4::Context->dbh;
+my $query=new CGI;
+my $lang=$query->cookie('KohaOpacLanguage');
+$lang="en" unless $lang;
+my @facets;
+my $sth=$dbh->prepare("SELECT facets_label_$lang,kohafield FROM facets where (facets_label_$lang<>'' ) group by facets_label_$lang");
+my $sth2=$dbh->prepare("SELECT * FROM facets where facets_label_$lang=?");
+$sth->execute();
+while (my ($label,$kohafield)=$sth->fetchrow){
+ $sth2->execute($label);
+my (@tags, at subfield);
+ while (my $data=$sth2->fetchrow_hashref){
+ push @tags,$data->{tagfield} ;
+ push @subfield,$data->{subfield} ;
+ }
+ my $facet = {
+ link_value =>"kohafield=$kohafield",
+ label_value =>$label,
+ tags => \@tags,
+ subfield =>\@subfield,
+ } ;
+ push @facets,$facet;
+}
+ return \@facets;
+}
+
+
+
+1;
+__END__
+
+=back
+
+=head1 AUTHOR
+
+Koha Team
+
+=cut
Index: Labels.pm
===================================================================
RCS file: Labels.pm
diff -N Labels.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Labels.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,457 @@
+package C4::Labels;
+
+# Copyright 2006 Katipo Communications.
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+require Exporter;
+
+use vars qw($VERSION @ISA @EXPORT);
+#use Data::Dumper;
+use PDF::Reuse;
+
+
+$VERSION = 0.01;
+
+=head1 NAME
+
+C4::Labels - Functions for printing spine labels and barcodes in Koha
+
+=head1 FUNCTIONS
+
+=over 2
+
+=cut
+
+ at ISA = qw(Exporter);
+ at EXPORT = qw(
+ &get_label_options &get_label_items
+ &build_circ_barcode &draw_boundaries
+ &draw_box
+);
+
+=item get_label_options;
+
+ $options = get_label_options()
+
+
+Return a pointer on a hash list containing info from labels_conf table in Koha DB.
+
+=cut
+#'
+sub get_label_options {
+ my $dbh = C4::Context->dbh;
+ my $query2 = " SELECT * FROM labels_conf LIMIT 1 ";
+ my $sth = $dbh->prepare($query2);
+ $sth->execute();
+ my $conf_data = $sth->fetchrow_hashref;
+ $sth->finish;
+ return $conf_data;
+}
+
+=item get_label_items;
+
+ $options = get_label_items()
+
+
+Returns an array of references-to-hash, whos keys are the field from the biblio, biblioitems, items and labels tables in the Koha database.
+
+=cut
+#'
+sub get_label_items {
+ my $dbh = C4::Context->dbh;
+
+ # get the actual items to be printed.
+ my @data;
+ my $query3 = " Select * from labels ";
+ my $sth = $dbh->prepare($query3);
+ $sth->execute();
+ my @resultsloop;
+ my $cnt = $sth->rows;
+ my $i1 = 1;
+ while ( my $data = $sth->fetchrow_hashref ) {
+
+ # lets get some summary info from each item
+ my $query1 =
+ " select * from biblio, biblioitems, items where itemnumber = ? and
+ items.biblioitemnumber=biblioitems.biblioitemnumber and
+ biblioitems.biblionumber=biblio.biblionumber";
+
+ my $sth1 = $dbh->prepare($query1);
+ $sth1->execute( $data->{'itemnumber'} );
+ my $data1 = $sth1->fetchrow_hashref();
+
+ push( @resultsloop, $data1 );
+ $sth1->finish;
+
+ $i1++;
+ }
+ $sth->finish;
+ return @resultsloop;
+}
+
+=item build_circ_barcode;
+
+ build_circ_barcode( $x_pos, $y_pos, $barcode,
+ $barcodetype, \$item);
+
+$item is the result of a previous call to get_label_items();
+
+=cut
+#'
+sub build_circ_barcode {
+ my ( $x_pos_circ, $y_pos, $value, $barcodetype, $item ) = @_;
+
+#warn Dumper \$item;
+
+ #warn "value = $value\n";
+
+ #$DB::single = 1;
+
+ if ( $barcodetype eq 'EAN13' ) {
+
+ #testing EAN13 barcodes hack
+ $value = $value . '000000000';
+ $value =~ s/-//;
+ $value = substr( $value, 0, 12 );
+
+ #warn $value;
+ eval {
+ PDF::Reuse::Barcode::EAN13(
+ x => ( $x_pos_circ + 27 ),
+ y => ( $y_pos + 15 ),
+ value => $value,
+
+ # prolong => 2.96,
+ # xSize => 1.5,
+
+ # ySize => 1.2,
+
+# added for xpdf compat. doesnt use type3 fonts., but increases filesize from 20k to 200k
+# i think its embedding extra fonts in the pdf file.
+# mode => 'graphic',
+ );
+ };
+ if ($@) {
+ $item->{'barcodeerror'} = 1;
+ #warn "EAN13BARCODE FAILED:$@";
+ }
+
+ #warn $barcodetype;
+
+ }
+ elsif ( $barcodetype eq 'Code39' ) {
+
+ eval {
+ PDF::Reuse::Barcode::Code39(
+ x => ( $x_pos_circ + 9 ),
+ y => ( $y_pos + 15 ),
+ value => $value,
+
+ # prolong => 2.96,
+ xSize => .85,
+
+ ySize => 1.3,
+ );
+ };
+ if ($@) {
+ $item->{'barcodeerror'} = 1;
+ #warn "CODE39BARCODE $value FAILED:$@";
+ }
+
+ #warn $barcodetype;
+
+ }
+
+ elsif ( $barcodetype eq 'Matrix2of5' ) {
+
+ #warn "MATRIX ELSE:";
+
+ #testing MATRIX25 barcodes hack
+ # $value = $value.'000000000';
+ $value =~ s/-//;
+
+ # $value = substr( $value, 0, 12 );
+ #warn $value;
+
+ eval {
+ PDF::Reuse::Barcode::Matrix2of5(
+ x => ( $x_pos_circ + 27 ),
+ y => ( $y_pos + 15 ),
+ value => $value,
+
+ # prolong => 2.96,
+ # xSize => 1.5,
+
+ # ySize => 1.2,
+ );
+ };
+ if ($@) {
+ $item->{'barcodeerror'} = 1;
+ #warn "BARCODE FAILED:$@";
+ }
+
+ #warn $barcodetype;
+
+ }
+
+ elsif ( $barcodetype eq 'EAN8' ) {
+
+ #testing ean8 barcodes hack
+ $value = $value . '000000000';
+ $value =~ s/-//;
+ $value = substr( $value, 0, 8 );
+
+ #warn $value;
+
+ #warn "EAN8 ELSEIF";
+ eval {
+ PDF::Reuse::Barcode::EAN8(
+ x => ( $x_pos_circ + 42 ),
+ y => ( $y_pos + 15 ),
+ value => $value,
+ prolong => 2.96,
+ xSize => 1.5,
+
+ # ySize => 1.2,
+ );
+ };
+
+ if ($@) {
+ $item->{'barcodeerror'} = 1;
+ #warn "BARCODE FAILED:$@";
+ }
+
+ #warn $barcodetype;
+
+ }
+
+ elsif ( $barcodetype eq 'UPC-E' ) {
+ eval {
+ PDF::Reuse::Barcode::UPCE(
+ x => ( $x_pos_circ + 27 ),
+ y => ( $y_pos + 15 ),
+ value => $value,
+ prolong => 2.96,
+ xSize => 1.5,
+
+ # ySize => 1.2,
+ );
+ };
+
+ if ($@) {
+ $item->{'barcodeerror'} = 1;
+ #warn "BARCODE FAILED:$@";
+ }
+
+ #warn $barcodetype;
+
+ }
+ elsif ( $barcodetype eq 'NW7' ) {
+ eval {
+ PDF::Reuse::Barcode::NW7(
+ x => ( $x_pos_circ + 27 ),
+ y => ( $y_pos + 15 ),
+ value => $value,
+ prolong => 2.96,
+ xSize => 1.5,
+
+ # ySize => 1.2,
+ );
+ };
+
+ if ($@) {
+ $item->{'barcodeerror'} = 1;
+ #warn "BARCODE FAILED:$@";
+ }
+
+ #warn $barcodetype;
+
+ }
+ elsif ( $barcodetype eq 'ITF' ) {
+ eval {
+ PDF::Reuse::Barcode::ITF(
+ x => ( $x_pos_circ + 27 ),
+ y => ( $y_pos + 15 ),
+ value => $value,
+ prolong => 2.96,
+ xSize => 1.5,
+
+ # ySize => 1.2,
+ );
+ };
+
+ if ($@) {
+ $item->{'barcodeerror'} = 1;
+ #warn "BARCODE FAILED:$@";
+ }
+
+ #warn $barcodetype;
+
+ }
+ elsif ( $barcodetype eq 'Industrial2of5' ) {
+ eval {
+ PDF::Reuse::Barcode::Industrial2of5(
+ x => ( $x_pos_circ + 27 ),
+ y => ( $y_pos + 15 ),
+ value => $value,
+ prolong => 2.96,
+ xSize => 1.5,
+
+ # ySize => 1.2,
+ );
+ };
+ if ($@) {
+ $item->{'barcodeerror'} = 1;
+ #warn "BARCODE FAILED:$@";
+ }
+
+ #warn $barcodetype;
+
+ }
+ elsif ( $barcodetype eq 'IATA2of5' ) {
+ eval {
+ PDF::Reuse::Barcode::IATA2of5(
+ x => ( $x_pos_circ + 27 ),
+ y => ( $y_pos + 15 ),
+ value => $value,
+ prolong => 2.96,
+ xSize => 1.5,
+
+ # ySize => 1.2,
+ );
+ };
+ if ($@) {
+ $item->{'barcodeerror'} = 1;
+ #warn "BARCODE FAILED:$@";
+ }
+
+ #warn $barcodetype;
+
+ }
+
+ elsif ( $barcodetype eq 'COOP2of5' ) {
+ eval {
+ PDF::Reuse::Barcode::COOP2of5(
+ x => ( $x_pos_circ + 27 ),
+ y => ( $y_pos + 15 ),
+ value => $value,
+ prolong => 2.96,
+ xSize => 1.5,
+
+ # ySize => 1.2,
+ );
+ };
+ if ($@) {
+ $item->{'barcodeerror'} = 1;
+ #warn "BARCODE FAILED:$@";
+ }
+
+ #warn $barcodetype;
+
+ }
+ elsif ( $barcodetype eq 'UPC-A' ) {
+
+ eval {
+ PDF::Reuse::Barcode::UPCA(
+ x => ( $x_pos_circ + 27 ),
+ y => ( $y_pos + 15 ),
+ value => $value,
+ prolong => 2.96,
+ xSize => 1.5,
+
+ # ySize => 1.2,
+ );
+ };
+ if ($@) {
+ $item->{'barcodeerror'} = 1;
+ #warn "BARCODE FAILED:$@";
+ }
+
+ #warn $barcodetype;
+
+ }
+
+}
+
+=item draw_boundaries
+
+ sub draw_boundaries ($x_pos_spine, $x_pos_circ1, $x_pos_circ2,
+ $y_pos, $spine_width, $label_height, $circ_width)
+
+This sub draws boundary lines where the label outlines are, to aid in printer testing, and debugging.
+
+=cut
+
+#'
+sub draw_boundaries {
+
+ my ($x_pos_spine, $x_pos_circ1, $x_pos_circ2,
+ $y_pos, $spine_width, $label_height, $circ_width) = @_;
+
+ my $y_pos_initial = ( ( 792 - 36 ) - 90 );
+ my $y_pos = $y_pos_initial;
+ my $i = 1;
+
+ for ( $i = 1 ; $i <= 8 ; $i++ ) {
+
+ &drawbox( $x_pos_spine, $y_pos, ($spine_width), ($label_height) );
+
+ #warn "OLD BOXES x=$x_pos_spine, y=$y_pos, w=$spine_width, h=$label_height";
+ &drawbox( $x_pos_circ1, $y_pos, ($circ_width), ($label_height) );
+ &drawbox( $x_pos_circ2, $y_pos, ($circ_width), ($label_height) );
+
+ $y_pos = ( $y_pos - $label_height );
+
+ }
+}
+
+=item drawbox
+
+ sub drawbox { $lower_left_x, $lower_left_y,
+ $upper_right_x, $upper_right_y )
+
+this is a low level sub, that draws a pdf box, it is called by draw_boxes
+
+=cut
+
+#'
+sub drawbox {
+ my ( $llx, $lly, $urx, $ury ) = @_;
+
+ my $str = "q\n"; # save the graphic state
+ $str .= "1.0 0.0 0.0 RG\n"; # border color red
+ $str .= "1 1 1 rg\n"; # fill color blue
+ $str .= "$llx $lly $urx $ury re\n"; # a rectangle
+ $str .= "B\n"; # fill (and a little more)
+ $str .= "Q\n"; # save the graphic state
+
+ prAdd($str);
+
+}
+
+
+1;
+__END__
+
+=back
+
+=head1 AUTHOR
+
+Mason James <mason at katipo.co.nz>
+=cut
+
Index: Letters.pm
===================================================================
RCS file: Letters.pm
diff -N Letters.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Letters.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,274 @@
+package C4::Letters;
+
+
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+use Mail::Sendmail;
+use C4::Date;
+use C4::Suggestions;
+use C4::Members;
+require Exporter;
+
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
+
+# set the version for version checking
+$VERSION = 0.01;
+
+=head1 NAME
+
+C4::Letters - Give functions for Letters management
+
+=head1 SYNOPSIS
+
+ use C4::Letters;
+
+=head1 DESCRIPTION
+
+ "Letters" is the tool used in Koha to manage informations sent to the patrons and/or the library. This include some cron jobs like
+ late issues, as well as other tasks like sending a mail to users that have subscribed to a "serial issue alert" (= being warned every time a new issue has arrived at the library)
+
+ Letters are managed through "alerts" sent by Koha on some events. All "alert" related functions are in this module too.
+
+=cut
+
+ at ISA = qw(Exporter);
+ at EXPORT = qw(&GetLetterList &getletter &addalert &getalert &delalert &findrelatedto &sendalerts);
+
+=head2 GetLetterList
+
+ parameter : $module : the name of the module
+ This sub returns an array of hashes with all letters from a given module
+ Each hash entry contains :
+ - module : the module name
+ - code : the code of the letter, char(20)
+ - name : the complete name of the letter, char(200)
+ - title : the title that will be used as "subject" in mails, char(200)
+ - content : the content of the letter. Each field to be replaced by a value at runtime is enclosed in << and >>. The fields usually have the same name as in the DB
+
+=cut
+
+sub GetLetterList {
+ my ($module) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("select * from letter where module=?");
+ $sth->execute($module);
+ my @result;
+ while (my $line = $sth->fetchrow_hashref) {
+ push @result,$line;
+ }
+ return @result;
+}
+
+sub getletter {
+ my ($module,$code) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("select * from letter where module=? and code=?");
+ $sth->execute($module,$code);
+ my $line = $sth->fetchrow_hashref;
+ return $line;
+}
+
+=head2 addalert
+
+ parameters :
+ - $borrowernumber : the number of the borrower subscribing to the alert
+ - $type : the type of alert.
+ - externalid : the primary key of the object to put alert on. For issues, the alert is made on subscriptionid.
+
+ create an alert and return the alertid (primary key)
+
+=cut
+
+sub addalert {
+ my ($borrowernumber,$type,$externalid) = @_;
+ my $dbh=C4::Context->dbh;
+ my $sth = $dbh->prepare("insert into alert (borrowernumber, type, externalid) values (?,?,?)");
+ $sth->execute($borrowernumber,$type,$externalid);
+ # get the alert number newly created and return it
+ my $alertid = $dbh->{'mysql_insertid'};
+ return $alertid;
+}
+
+=head2 delalert
+ parameters :
+ - alertid : the alert id
+ deletes the alert
+=cut
+
+sub delalert {
+ my ($alertid)=@_;
+# warn "ALERTID : $alertid";
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("delete from alert where alertid=?");
+ $sth->execute($alertid);
+}
+
+=head2 getalert
+
+ parameters :
+ - $borrowernumber : the number of the borrower subscribing to the alert
+ - $type : the type of alert.
+ - externalid : the primary key of the object to put alert on. For issues, the alert is made on subscriptionid.
+ all parameters NON mandatory. If a parameter is omitted, the query is done without the corresponding parameter. For example, without $externalid, returns all alerts for a borrower on a topic.
+
+=cut
+
+sub getalert {
+ my ($borrowernumber,$type,$externalid) = @_;
+ my $dbh=C4::Context->dbh;
+ my $query = "select * from alert where";
+ my @bind;
+ if ($borrowernumber) {
+ $query .= " borrowernumber=? and";
+ push @bind,$borrowernumber;
+ }
+ if ($type) {
+ $query .= " type=? and";
+ push @bind,$type;
+ }
+ if ($externalid) {
+ $query .= " externalid=? and";
+ push @bind,$externalid;
+ }
+ $query =~ s/ and$//;
+ my $sth = $dbh->prepare($query);
+ $sth->execute(@bind);
+ my @result;
+ while (my $line = $sth->fetchrow_hashref) {
+ push @result,$line;
+ }
+ return \@result if $#result >=0; # return only if there is one result.
+ return;
+}
+
+=head2 findrelatedto
+ parameters :
+ - $type : the type of alert
+ - $externalid : the id of the "object" to query
+
+ In the table alert, a "id" is stored in the externalid field. This "id" is related to another table, depending on the type of the alert.
+ When type=issue, the id is related to a subscriptionid and this sub returns the name of the biblio.
+ When type=virtual, the id is related to a virtual shelf and this sub returns the name of the sub
+=cut
+
+sub findrelatedto {
+ my ($type,$externalid) = @_;
+ my $dbh=C4::Context->dbh;
+ my $sth;
+ if ($type eq 'issue') {
+ $sth=$dbh->prepare("select title as result from subscription left join biblio on subscription.biblionumber=biblio.biblionumber where subscriptionid=?");
+ }
+ if ($type eq 'borrower') {
+ $sth=$dbh->prepare("select concat(firstname,' ',surname) from borrowers where borrowernumber=?");
+ }
+ $sth->execute($externalid);
+ my ($result) = $sth->fetchrow;
+ return $result;
+}
+
+=head2 sendalert
+ parameters :
+ - $type : the type of alert
+ - $externalid : the id of the "object" to query
+ - $letter : the letter to send.
+
+ send an alert to all borrowers having put an alert on a given subject.
+
+=cut
+
+sub sendalerts {
+ my ($type,$externalid,$letter)=@_;
+ my $dbh=C4::Context->dbh;
+ if ($type eq 'issue') {
+# warn "sending issues...";
+ my $letter = getletter('serial',$letter);
+ # prepare the letter...
+ # search the biblionumber
+ my $sth=$dbh->prepare("select biblionumber from subscription where subscriptionid=?");
+ $sth->execute($externalid);
+ my ($biblionumber)=$sth->fetchrow;
+ # parsing branch info
+ my $userenv = C4::Context->userenv;
+ parseletter($letter,'branches',$userenv->{branch});
+ # parsing librarian name
+ $letter->{content} =~ s/<<LibrarianFirstname>>/$userenv->{firstname}/g;
+ $letter->{content} =~ s/<<LibrarianSurname>>/$userenv->{surname}/g;
+ $letter->{content} =~ s/<<LibrarianEmailaddress>>/$userenv->{emailaddress}/g;
+ # parsing biblio information
+ parseletter($letter,'biblio',$biblionumber);
+ parseletter($letter,'biblioitems',$biblionumber);
+ # find the list of borrowers to alert
+ my $alerts = getalert('','issue',$externalid);
+ foreach (@$alerts) {
+ # and parse borrower ...
+ my $innerletter = $letter;
+ my $borinfo = getmember('',$_->{'borrowernumber'});
+ parseletter($innerletter,'borrowers',$_->{'borrowernumber'});
+ # ... then send mail
+ if ($borinfo->{emailaddress}) {
+ my %mail = ( To => $borinfo->{emailaddress},
+ From => $userenv->{emailaddress},
+ Subject => "".$innerletter->{title},
+ Message => "".$innerletter->{content},
+ );
+ sendmail(%mail);
+# warn "sending to $mail{To} From $mail{From} subj $mail{Subject} Mess $mail{Message}";
+ }
+ }
+ }
+}
+
+=head2
+ parameters :
+ - $letter : a hash to letter fields (title & content useful)
+ - $table : the Koha table to parse.
+ - $pk : the primary key to query on the $table table
+ parse all fields from a table, and replace values in title & content with the appropriate value
+ (not exported sub, used only internally)
+=cut
+sub parseletter {
+ my ($letter,$table,$pk) = @_;
+# warn "Parseletter : ($letter,$table,$pk)";
+ my $dbh=C4::Context->dbh;
+ my $sth;
+ if ($table eq 'biblio') {
+ $sth = $dbh->prepare("select * from biblio where biblionumber=?");
+ } elsif ($table eq 'biblioitems') {
+ $sth = $dbh->prepare("select * from biblioitems where biblionumber=?");
+ } elsif ($table eq 'borrowers') {
+ $sth = $dbh->prepare("select * from borrowers where borrowernumber=?");
+ } elsif ($table eq 'branches') {
+ $sth = $dbh->prepare("select * from branches where branchcode=?");
+ }
+ $sth->execute($pk);
+ # store the result in an hash
+ my $values = $sth->fetchrow_hashref;
+ # and get all fields from the table
+ $sth = $dbh->prepare("show columns from $table");
+ $sth->execute;
+ while ((my $field) = $sth->fetchrow_array) {
+ my $replacefield="<<$table.$field>>";
+ my $replacedby = $values->{$field};
+# warn "REPLACE $replacefield by $replacedby";
+ $letter->{title} =~ s/$replacefield/$replacedby/g;
+ $letter->{content} =~ s/$replacefield/$replacedby/g;
+ }
+}
+
+END { } # module clean-up code here (global destructor)
Index: Log.pm
===================================================================
RCS file: Log.pm
diff -N Log.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Log.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,202 @@
+package C4::Log; #assumes C4/Log
+
+#package to deal with Logging Actions in DB
+
+
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+use C4::Context;
+use C4::Date;
+
+require Exporter;
+
+use vars qw($VERSION @ISA @EXPORT);
+
+# set the version for version checking
+$VERSION = 0.01;
+
+=head1 NAME
+
+C4::Log - Koha Log Facility functions
+
+=head1 SYNOPSIS
+
+ use C4::Log;
+
+=head1 DESCRIPTION
+
+The functions in this module perform various functions in order to log all the operations done on the Database, including deleting and undeleting books, adding/editing members, etc.
+
+=head1 FUNCTIONS
+
+=over 2
+
+=cut
+
+ at ISA = qw(Exporter);
+ at EXPORT = qw(&logaction &logstatus &displaylog);
+
+=item logaction
+
+ &logaction($usernumber, $modulename, $actionname, $infos);
+
+Adds a record into action_logs table to report the different changes upon the database
+
+=cut
+#'
+sub logaction{
+ my ($usernumber,$modulename, $actionname, $objectnumber, $infos)=@_;
+ $usernumber='' unless $usernumber;
+ my $dbh = C4::Context->dbh;
+ my $sth=$dbh->prepare("Insert into action_logs (timestamp,user,module,action,object,info) values (now(),?,?,?,?,?)");
+ $sth->execute($usernumber,$modulename,$actionname,$objectnumber,$infos);
+ $sth->finish;
+}
+
+=item logstatus
+
+ &logstatus;
+
+returns True If Activate_Log variable is equal to On
+Activate_Log is a system preference Variable
+=cut
+#'
+sub logstatus{
+ return C4::Context->preference("Activate_Log");
+}
+
+=item displaylog
+
+ &displaylog($modulename, @filters);
+ $modulename is the name of the module on which the user wants to display logs
+ @filters is an optional table of hash containing :
+ - name : the name of the variable to filter
+ - value : the value of the filter.... May be with * joker
+
+returns a table of hash containing who did what on which object at what time
+
+=cut
+#'
+sub displaylog{
+ my ($modulename, @filters)=@_;
+ my $dbh = C4::Context->dbh;
+ my $strsth;
+ if ($modulename eq "cataloguing"){
+ $strsth="select action_logs.timestamp, action_logs.action, action_logs.info, borrowers.cardnumber, borrowers.surname, borrowers.firstname, borrowers.userid,";
+ $strsth .= "biblio.biblionumber, biblio.title, biblio.author" ;#if ($modulename eq "acqui.simple");
+ $strsth .= " FROM borrowers,action_logs ";
+ $strsth .= ",biblio " ;#if ($modulename eq "acqui.simple");
+
+ $strsth .=" WHERE borrowers.borrowernumber=action_logs.user";
+ $strsth .=" AND action_logs.module = 'cataloguing' AND action_logs.object=biblio.biblionumber ";# if ($modulename eq "acqui.simple");
+ if (@filters){
+ foreach my $filter (@filters){
+ if ($filter->{name} =~ /user/){
+ $filter->{value}=~s/\*/%/g;
+ $strsth .= " AND borrowers.surname like ".$filter->{value};
+ }elsif ($filter->{name} =~ /title/){
+ $filter->{value}=~s/\*/%/g;
+ $strsth .= " AND biblio.title like ".$filter->{value};
+ }elsif ($filter->{name} =~ /author/){
+ $filter->{value}=~s/\*/%/g;
+ $strsth .= " AND biblio.author like ".$filter->{value};
+ }
+ }
+ }
+ } elsif ($modulename eq "circulation") {
+ $strsth="select a.timestamp, a.action, a.info,a.object, b.cardnumber, b.surname, b.firstname, bi.biblionumber, bi.title, bi.author,b2.firstname as first,b2.surname as last FROM action_logs a ";
+
+ $strsth.=" LEFT JOIN borrowers b on b.borrowernumber=a.user ";
+ $strsth.=" LEFT JOIN borrowers b2 on b2.borrowernumber=a.info ";
+ $strsth.=" LEFT JOIN items i on i.barcode=a.object ";
+ $strsth.=" LEFT JOIN biblio bi on bi.biblionumber=i.biblionumber";
+ $strsth .= " WHERE a.module = 'circulation' ";# if ($modulename eq "circulation");
+ if (@filters){
+ foreach my $filter (@filters){
+ if ($filter->{name} =~ /user/){
+ $filter->{value}=~s/\*/%/g;
+ $strsth .= " AND borrowers.surname like ".$filter->{value};
+ }elsif ($filter->{name} =~ /title/){
+ $filter->{value}=~s/\*/%/g;
+ $strsth .= " AND biblio.title like ".$filter->{value};
+ }elsif ($filter->{name} =~ /action/){
+ $strsth .= " AND a.action= '$filter->{value}'";
+ }elsif ($filter->{name} =~ /from/){
+ $strsth .= " AND a.timestamp> '$filter->{value}'";
+ }elsif ($filter->{name} =~ /to/){
+ $strsth .= " AND a.timestamp<= '$filter->{value}'";
+ }
+ }
+ }
+ } elsif ($modulename eq "members"){
+ $strsth="select a.timestamp, a.action,a.info, a.object, b.surname, b.firstname, ";
+ $strsth .= "bor2.cardnumber as card, bor2.surname as last, bor2.firstname as first, bor2.userid as user";
+ $strsth .= " FROM action_logs a ";
+ $strsth.=" LEFT JOIN borrowers b on b.borrowernumber=a.user ";
+ $strsth.=" LEFT JOIN borrowers bor2 on bor2.borrowernumber=a.object ";
+ $strsth .= " WHERE a.module = 'members' ";# if ($modulename eq "acqui.simple");
+ if (@filters){
+ foreach my $filter (@filters){
+ if ($filter->{name} =~ /user/){
+ $filter->{value}=~s/\*/%/g;
+ $strsth .= " AND b.surname like ".$filter->{value};
+ }elsif ($filter->{name} =~ /surname/){
+ $filter->{value}=~s/\*/%/g;
+ $strsth .= " AND bor2.surname like ".$filter->{value};
+ }elsif ($filter->{name} =~ /firstname/){
+ $filter->{value}=~s/\*/%/g;
+ $strsth .= " AND bor2.firsntame like ".$filter->{value};
+ }elsif ($filter->{name} =~ /cardnumber/){
+ $filter->{value}=~s/\*/%/g;
+ $strsth .= " AND bor2.cardnumber like ".$filter->{value};
+ }elsif ($filter->{name} =~ /action/){
+ $strsth .= " AND a.action= '$filter->{value}'";
+ }
+ }
+ }
+ }
+# warn "displaylog :".$strsth;
+ if ($strsth){
+ my $sth=$dbh->prepare($strsth);
+ $sth->execute;
+ my @results;
+ my $count;
+ my $hilighted=1;
+ while (my $data = $sth->fetchrow_hashref){
+ $data->{hilighted} = ($hilighted>0);
+ $data->{info} =~ s/\n/<br\/>/g;
+ $data->{day} = format_date($data->{timestamp});
+ push @results, $data;
+ $count++;
+ $hilighted = -$hilighted;
+ }
+ return ($count, \@results);
+ } else {return 0;}
+}
+
+1;
+__END__
+
+=back
+
+=head1 AUTHOR
+
+Koha Developement team <info at koha.org>
+
+=cut
Index: Members.pm
===================================================================
RCS file: Members.pm
diff -N Members.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Members.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,1655 @@
+# -*- tab-width: 8 -*-
+
+package C4::Members;
+
+# Copyright 2000-2003 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+# $Id: Members.pm,v 1.1.2.1 2007/03/10 01:35:34 tgarip1957 Exp $
+
+use strict;
+require Exporter;
+use C4::Context;
+use C4::Date;
+use Digest::MD5 qw(md5_base64);
+use C4::Biblio;
+use C4::Stats;
+use C4::Reserves2;
+use C4::Koha;
+use C4::Accounts2;
+
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
+
+$VERSION = do { my @v = '$Revision: 1.1.2.1 $' =~ /\d+/g; shift(@v) . "." . join( "_", map { sprintf "%03d", $_ } @v ); };
+
+=head1 NAME
+
+C4::Members - Perl Module containing convenience functions for member handling
+
+=head1 SYNOPSIS
+
+use C4::Members;
+
+=head1 DESCRIPTION
+
+This module contains routines for adding, modifying and deleting members/patrons/borrowers
+
+=head1 FUNCTIONS
+
+=over 2
+
+=cut
+
+#'
+
+ at ISA = qw(Exporter);
+
+ at EXPORT = qw(
+&allissues
+&add_member_orgs
+&borrdata
+&borrdata2
+&borrdata3
+&BornameSearch
+&borrissues
+&borrowercard_active
+&borrowercategories
+&change_user_pass
+&checkuniquemember
+&calcexpirydate
+&checkuserpassword
+ðnicitycategories
+&fixEthnicity
+&fixup_cardnumber
+&findguarantees
+&findguarantor
+&fixupneu_cardnumber
+&getmember
+&getMemberPhoto
+&get_institutions
+&getzipnamecity
+&getidcity
+&getguarantordata
+&getcategorytype
+&getboracctrecord
+&getborrowercategory
+&getborrowercategoryinfo
+&get_age
+&getpatroninformation
+&GetBorrowersFromSurname
+&GetBranchCodeFromBorrowers
+&GetFlagsAndBranchFromBorrower
+&GuarantornameSearch
+&NewBorrowerNumber
+&modmember
+&newmember
+&expand_sex_into_predicate
+&patronflags
+ );
+
+
+
+=head2 borrowercategories
+
+ ($codes_arrayref, $labels_hashref) = &borrowercategories();
+
+Looks up the different types of borrowers in the database. Returns two
+elements: a reference-to-array, which lists the borrower category
+codes, and a reference-to-hash, which maps the borrower category codes
+to category descriptions.
+
+=cut
+#'
+
+sub borrowercategories {
+ my $dbh = C4::Context->dbh;
+ my $sth=$dbh->prepare("Select categorycode,description from categories order by description");
+ $sth->execute;
+ my %labels;
+ my @codes;
+ while (my $data=$sth->fetchrow_hashref){
+ push @codes,$data->{'categorycode'};
+ $labels{$data->{'categorycode'}}=$data->{'description'};
+ }
+ $sth->finish;
+ return(\@codes,\%labels);
+}
+
+=item BornameSearch
+
+ ($count, $borrowers) = &BornameSearch($env, $searchstring, $type);
+
+Looks up patrons (borrowers) by name.
+
+C<$env> is ignored.
+
+BUGFIX 499: C<$type> is now used to determine type of search.
+if $type is "simple", search is performed on the first letter of the
+surname only.
+
+C<$searchstring> is a space-separated list of search terms. Each term
+must match the beginning a borrower's surname, first name, or other
+name.
+
+C<&BornameSearch> returns a two-element list. C<$borrowers> is a
+reference-to-array; each element is a reference-to-hash, whose keys
+are the fields of the C<borrowers> table in the Koha database.
+C<$count> is the number of elements in C<$borrowers>.
+
+=cut
+#'
+#used by member enquiries from the intranet
+#called by member.pl
+sub BornameSearch {
+ my ($env,$searchstring,$orderby,$type)=@_;
+ my $dbh = C4::Context->dbh;
+ my $query = "";
+ my $count;
+ my @data;
+ my @bind=();
+
+ if($type eq "simple") # simple search for one letter only
+ {
+ $query="Select * from borrowers where surname like '$searchstring%' order by $orderby";
+# @bind=("$searchstring%");
+ }
+ else # advanced search looking in surname, firstname and othernames
+ {
+### Try to determine whether numeric like cardnumber
+ if ($searchstring+1>1) {
+ $query="Select * from borrowers where cardnumber like '$searchstring%' ";
+
+ }else{
+
+ my @words=split / /,$searchstring;
+ foreach my $word(@words){
+ $word="+".$word;
+
+ }
+ $searchstring=join " ", at words;
+
+ $query="Select * from borrowers where MATCH(surname,firstname,othernames) AGAINST('$searchstring' in boolean mode)";
+
+ }
+ $query=$query." order by $orderby";
+ }
+
+ my $sth=$dbh->prepare($query);
+# warn "Q $orderby : $query";
+ $sth->execute();
+ my @results;
+ my $cnt=$sth->rows;
+ while (my $data=$sth->fetchrow_hashref){
+ push(@results,$data);
+ }
+ # $sth->execute;
+ $sth->finish;
+ return ($cnt,\@results);
+}
+=head2 getpatroninformation
+
+ ($borrower, $flags) = &getpatroninformation($env, $borrowernumber, $cardnumber);
+Looks up a patron and returns information about him or her. If
+C<$borrowernumber> is true (nonzero), C<&getpatroninformation> looks
+up the borrower by number; otherwise, it looks up the borrower by card
+number.
+C<$env> is effectively ignored, but should be a reference-to-hash.
+C<$borrower> is a reference-to-hash whose keys are the fields of the
+borrowers table in the Koha database. In addition,
+C<$borrower-E<gt>{flags}> is a hash giving more detailed information
+about the patron. Its keys act as flags :
+
+ if $borrower->{flags}->{LOST} {
+ # Patron's card was reported lost
+ }
+
+Each flag has a C<message> key, giving a human-readable explanation of
+the flag. If the state of a flag means that the patron should not be
+allowed to borrow any more books, then it will have a C<noissues> key
+with a true value.
+
+The possible flags are:
+
+=head3 CHARGES
+
+=over 4
+
+Shows the patron's credit or debt, if any.
+
+=back
+
+=head3 GNA
+
+=over 4
+
+(Gone, no address.) Set if the patron has left without giving a
+forwarding address.
+
+=back
+
+=head3 LOST
+
+=over 4
+
+Set if the patron's card has been reported as lost.
+
+=back
+
+=head3 DBARRED
+
+=over 4
+
+Set if the patron has been debarred.
+
+=back
+
+=head3 NOTES
+
+=over 4
+
+Any additional notes about the patron.
+
+=back
+
+=head3 ODUES
+
+=over 4
+
+Set if the patron has overdue items. This flag has several keys:
+
+C<$flags-E<gt>{ODUES}{itemlist}> is a reference-to-array listing the
+overdue items. Its elements are references-to-hash, each describing an
+overdue item. The keys are selected fields from the issues, biblio,
+biblioitems, and items tables of the Koha database.
+
+C<$flags-E<gt>{ODUES}{itemlist}> is a string giving a text listing of
+the overdue items, one per line.
+
+=back
+
+=head3 WAITING
+
+=over 4
+
+Set if any items that the patron has reserved are available.
+
+C<$flags-E<gt>{WAITING}{itemlist}> is a reference-to-array listing the
+available items. Each element is a reference-to-hash whose keys are
+fields from the reserves table of the Koha database.
+
+=back
+
+=back
+
+=cut
+
+sub getpatroninformation {
+# returns
+ my ($env, $borrowernumber,$cardnumber) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query;
+ my $sth;
+ if ($borrowernumber) {
+ $sth = $dbh->prepare("select * from borrowers where borrowernumber=?");
+ $sth->execute($borrowernumber);
+ } elsif ($cardnumber) {
+ $sth = $dbh->prepare("select * from borrowers where cardnumber=?");
+ $sth->execute($cardnumber);
+ } else {
+ $env->{'apierror'} = "invalid borrower information passed to getpatroninformation subroutine";
+ return();
+ }
+ my $borrower = $sth->fetchrow_hashref;
+ my $amount = C4::Accounts2::checkaccount($env, $borrowernumber, $dbh);
+ $borrower->{'amountoutstanding'} = $amount;
+ my $flags = patronflags($env, $borrower, $dbh);
+ my $accessflagshash;
+
+ $sth=$dbh->prepare("select bit,flag from userflags");
+ $sth->execute;
+ while (my ($bit, $flag) = $sth->fetchrow) {
+ if ($borrower->{'flags'} & 2**$bit) {
+ $accessflagshash->{$flag}=1;
+ }
+ }
+ $sth->finish;
+ $borrower->{'flags'}=$flags;
+ $borrower->{'authflags'} = $accessflagshash;
+ return ($borrower); #, $flags, $accessflagshash);
+}
+
+=item getmember
+
+ $borrower = &getmember($cardnumber, $borrowernumber);
+
+Looks up information about a patron (borrower) by either card number
+or borrower number. If $borrowernumber is specified, C<&borrdata>
+searches by borrower number; otherwise, it searches by card number.
+
+C<&getmember> returns a reference-to-hash whose keys are the fields of
+the C<borrowers> table in the Koha database.
+
+=cut
+
+=head3 GetFlagsAndBranchFromBorrower
+
+=over 4
+
+($flags, $homebranch) = GetFlagsAndBranchFromBorrower($loggedinuser);
+
+this function read on the database to get flags and homebranch for a user
+given on input arg.
+
+return :
+it returns the $flags & the homebranch in scalar context.
+
+=back
+
+=cut
+
+
+
+=item borrissues
+
+ ($count, $issues) = &borrissues($borrowernumber);
+
+Looks up what the patron with the given borrowernumber has borrowed.
+
+C<&borrissues> returns a two-element array. C<$issues> is a
+reference-to-array, where each element is a reference-to-hash; the
+keys are the fields from the C<issues>, C<biblio>, and C<items> tables
+in the Koha database. C<$count> is the number of elements in
+C<$issues>.
+
+=cut
+#'
+sub borrissues {
+ my ($bornum)=@_;
+ my $dbh = C4::Context->dbh;
+ my $sth=$dbh->prepare("Select * from issues,biblio,items where borrowernumber=?
+ and items.itemnumber=issues.itemnumber
+ and items.biblionumber=biblio.biblionumber
+ and issues.returndate is NULL order by date_due");
+ $sth->execute($bornum);
+ my @result;
+ while (my $data = $sth->fetchrow_hashref) {
+ push @result, $data;
+ }
+ $sth->finish;
+ return(scalar(@result), \@result);
+}
+
+=item allissues
+
+ ($count, $issues) = &allissues($borrowernumber, $sortkey, $limit);
+
+Looks up what the patron with the given borrowernumber has borrowed,
+and sorts the results.
+
+C<$sortkey> is the name of a field on which to sort the results. This
+should be the name of a field in the C<issues>, C<biblio>,
+C<biblioitems>, or C<items> table in the Koha database.
+
+C<$limit> is the maximum number of results to return.
+
+C<&allissues> returns a two-element array. C<$issues> is a
+reference-to-array, where each element is a reference-to-hash; the
+keys are the fields from the C<issues>, C<biblio>, C<biblioitems>, and
+C<items> tables of the Koha database. C<$count> is the number of
+elements in C<$issues>
+
+=cut
+#'
+sub allissues {
+ my ($bornum,$order,$limit)=@_;
+ #FIXME: sanity-check order and limit
+ my $dbh = C4::Context->dbh;
+ my $query="Select * from issues,biblio,items
+ where borrowernumber=? and
+ items.itemnumber=issues.itemnumber and
+ items.biblionumber=biblio.biblionumber order by $order";
+ if ($limit !=0){
+ $query.=" limit $limit";
+ }
+ #print $query;
+ my $sth=$dbh->prepare($query);
+ $sth->execute($bornum);
+ my @result;
+ my $i=0;
+ while (my $data=$sth->fetchrow_hashref){
+ $result[$i]=$data;;
+ $i++;
+ }
+ $sth->finish;
+ return($i,\@result);
+}
+
+
+sub borrdata3 {
+## NEU specific. used in Reserve section issues
+ my ($env,$bornum)=@_;
+ my $dbh = C4::Context->dbh;
+ my $query="Select count(*) from reserveissue as r where r.borrowernumber='$bornum'
+ and rettime is null";
+ # print $query;
+ my $sth=$dbh->prepare($query);
+ $sth->execute;
+ my $data=$sth->fetchrow_hashref;
+ $sth->finish;
+ $sth=$dbh->prepare("Select count(*),timediff(now(), duetime ) as elapsed, hour(timediff(now(), duetime )) as hours, MINUTE(timediff(now(), duetime )) as min from
+ reserveissue as r where r.borrowernumber='$bornum' and rettime is null and duetime< now() group by r.borrowernumber");
+ $sth->execute;
+
+ my $data2=$sth->fetchrow_hashref;
+my $resfine;
+my $rescharge=C4::Context->preference('resmaterialcharge');
+ if (!$rescharge){
+ $rescharge=1;
+ }
+ if ($data2->{'elapsed'}>0){
+ $resfine=($data2->{'hours'}+$data2->{'min'}/60)*$rescharge;
+ $resfine=sprintf ("%.1f",$resfine);
+ }
+ $sth->finish;
+ $sth=$dbh->prepare("Select sum(amountoutstanding) from accountlines where
+ borrowernumber='$bornum'");
+ $sth->execute;
+ my $data3=$sth->fetchrow_hashref;
+ $sth->finish;
+
+
+return($data2->{'count(*)'},$data->{'count(*)'},$data3->{'sum(amountoutstanding)'},$resfine);
+}
+=item getboracctrecord
+
+ ($count, $acctlines, $total) = &getboracctrecord($env, $borrowernumber);
+
+Looks up accounting data for the patron with the given borrowernumber.
+
+C<$env> is ignored.
+
+
+C<&getboracctrecord> returns a three-element array. C<$acctlines> is a
+reference-to-array, where each element is a reference-to-hash; the
+keys are the fields of the C<accountlines> table in the Koha database.
+C<$count> is the number of elements in C<$acctlines>. C<$total> is the
+total amount outstanding for all of the account lines.
+
+=cut
+#'
+sub getboracctrecord {
+ my ($env,$params) = @_;
+ my $dbh = C4::Context->dbh;
+ my @acctlines;
+ my $numlines=0;
+ my $sth=$dbh->prepare("Select * from accountlines where
+borrowernumber=? order by date desc,timestamp desc");
+# print $query;
+ $sth->execute($params->{'borrowernumber'});
+ my $total=0;
+ while (my $data=$sth->fetchrow_hashref){
+ $acctlines[$numlines] = $data;
+ $numlines++;
+ $total += $data->{'amountoutstanding'};
+ }
+ $sth->finish;
+ return ($numlines,\@acctlines,$total);
+}
+
+sub getborrowercategory{
+ my ($catcode) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("SELECT description FROM categories WHERE categorycode = ?");
+ $sth->execute($catcode);
+ my $description = $sth->fetchrow();
+ $sth->finish();
+ return $description;
+} # sub getborrowercategory
+
+sub getborrowercategoryinfo{
+ my ($catcode) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("SELECT * FROM categories WHERE categorycode = ?");
+ $sth->execute($catcode);
+ my $category = $sth->fetchrow_hashref;
+ $sth->finish();
+ return $category;
+} # sub getborrowercategoryinfo
+
+
+sub GetFlagsAndBranchFromBorrower {
+ my $loggedinuser = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = "
+ SELECT flags, branchcode
+ FROM borrowers
+ WHERE borrowernumber = ?
+ ";
+ my $sth = $dbh->prepare($query);
+ $sth->execute($loggedinuser);
+
+ return $sth->fetchrow;
+}
+
+
+sub getmember {
+ my ( $cardnumber, $bornum ) = @_;
+ $cardnumber = uc $cardnumber;
+ my $dbh = C4::Context->dbh;
+ my $sth;
+ if ( $bornum eq '' ) {
+ $sth = $dbh->prepare("Select * from borrowers where cardnumber=?");
+ $sth->execute($cardnumber);
+ } else {
+ $sth = $dbh->prepare("Select * from borrowers where borrowernumber=?");
+ $sth->execute($bornum);
+ }
+ my $data = $sth->fetchrow_hashref;
+ $sth->finish;
+ if ($data) {
+ return ($data);
+ }
+ else { # try with firstname
+ if ($cardnumber) {
+ my $sth =
+ $dbh->prepare("select * from borrowers where firstname=?");
+ $sth->execute($cardnumber);
+ my $data = $sth->fetchrow_hashref;
+ $sth->finish;
+ return ($data);
+ }
+ }
+ return undef;
+}
+
+=item borrdata
+
+ $borrower = &borrdata($cardnumber, $borrowernumber);
+
+Looks up information about a patron (borrower) by either card number
+or borrower number. If $borrowernumber is specified, C<&borrdata>
+searches by borrower number; otherwise, it searches by card number.
+
+C<&borrdata> returns a reference-to-hash whose keys are the fields of
+the C<borrowers> table in the Koha database.
+
+=cut
+
+#'
+sub borrdata {
+ my ( $cardnumber, $bornum ) = @_;
+ $cardnumber = uc $cardnumber;
+ my $dbh = C4::Context->dbh;
+ my $sth;
+ if ( $bornum eq '' ) {
+ $sth =
+ $dbh->prepare(
+"Select borrowers.*,categories.category_type from borrowers left join categories on borrowers.categorycode=categories.categorycode where cardnumber=?"
+ );
+ $sth->execute($cardnumber);
+ }
+ else {
+ $sth =
+ $dbh->prepare(
+"Select borrowers.*,categories.category_type from borrowers left join categories on borrowers.categorycode=categories.categorycode where borrowernumber=?"
+ );
+ $sth->execute($bornum);
+ }
+ my $data = $sth->fetchrow_hashref;
+# warn "DATA" . $data->{category_type};
+ $sth->finish;
+ if ($data) {
+ return ($data);
+ }
+ else { # try with firstname
+ if ($cardnumber) {
+ my $sth =
+ $dbh->prepare(
+"Select borrowers.*,categories.category_type from borrowers left join categories on borrowers.categorycode=categories.categorycode where firstname=?"
+ );
+ $sth->execute($cardnumber);
+ my $data = $sth->fetchrow_hashref;
+ $sth->finish;
+ return ($data);
+ }
+ }
+ return undef;
+}
+
+=item borrdata2
+
+ ($borrowed, $due, $fine) = &borrdata2($env, $borrowernumber);
+
+Returns aggregate data about items borrowed by the patron with the
+given borrowernumber.
+
+C<$env> is ignored.
+
+C<&borrdata2> returns a three-element array. C<$borrowed> is the
+number of books the patron currently has borrowed. C<$due> is the
+number of overdue items the patron currently has borrowed. C<$fine> is
+the total fine currently due by the borrower.
+
+=cut
+
+#'
+sub borrdata2 {
+ my ( $env, $bornum ) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = "Select count(*) from issues where borrowernumber='$bornum' and
+ returndate is NULL";
+
+ # print $query;
+ my $sth = $dbh->prepare($query);
+ $sth->execute;
+ my $data = $sth->fetchrow_hashref;
+ $sth->finish;
+ $sth = $dbh->prepare(
+ "Select count(*) from issues where
+ borrowernumber='$bornum' and date_due < now() and returndate is NULL"
+ );
+ $sth->execute;
+ my $data2 = $sth->fetchrow_hashref;
+ $sth->finish;
+ $sth = $dbh->prepare(
+ "Select sum(amountoutstanding) from accountlines where
+ borrowernumber='$bornum'"
+ );
+ $sth->execute;
+ my $data3 = $sth->fetchrow_hashref;
+ $sth->finish;
+
+ return ( $data2->{'count(*)'}, $data->{'count(*)'},
+ $data3->{'sum(amountoutstanding)'} );
+}
+
+sub modmember {
+ my (%data) = @_;
+ my $dbh = C4::Context->dbh;
+ $data{'dateofbirth'}=format_date_in_iso($data{'dateofbirth'});
+
+
+ $data{'joining'}=format_date_in_iso($data{'joining'});
+
+ if ($data{'expiry'}) {
+ $data{'expiry'}=format_date_in_iso($data{'expiry'});
+ }else{
+
+ $data{'expiry'} = calcexpirydate($data{'categorycode'},$data{'joining'} );
+
+ }
+
+ my $query= "UPDATE borrowers SET
+ cardnumber = '$data{'cardnumber'}' ,
+ surname = '$data{'surname'}' ,
+ firstname = '$data{'firstname'}' ,
+ title = '$data{'title'}' ,
+ initials = '$data{'initials'}' ,
+ dateofbirth = '$data{'dateofbirth'}' ,
+ sex = '$data{'sex'}' ,
+ streetaddress = '$data{'streetaddress'}' ,
+ streetcity = '$data{'streetcity'}' ,
+ zipcode = '$data{'zipcode'}' ,
+ phoneday = '$data{'phoneday'}' ,
+ physstreet = '$data{'physstreet'}' ,
+ city = '$data{'city'}' ,
+ homezipcode = '$data{'homezipcode'}' ,
+ phone = '$data{'phone'}' ,
+ emailaddress = '$data{'emailaddress'}' ,
+ preferredcont = '$data{'preferredcont'}',
+ faxnumber = '$data{'faxnumber'}' ,
+ textmessaging = '$data{'textmessaging'}' ,
+ categorycode = '$data{'categorycode'}' ,
+ branchcode = '$data{'branchcode'}' ,
+ borrowernotes = '$data{'borrowernotes'}' ,
+ ethnicity = '$data{'ethnicity'}' ,
+ ethnotes = '$data{'ethnotes'}' ,
+ expiry = '$data{'expiry'}' ,
+ dateenrolled = '$data{'joining'}' ,
+ sort1 = '$data{'sort1'}' ,
+ sort2 = '$data{'sort2'}' ,
+ debarred = '$data{'debarred'}' ,
+ lost = '$data{'lost'}' ,
+ gonenoaddress = '$data{'gna'}'
+ WHERE borrowernumber = $data{'borrowernumber'}";
+ my $sth = $dbh->prepare($query);
+ $sth->execute;
+ $sth->finish;
+ # ok if its an adult (type) it may have borrowers that depend on it as a guarantor
+ # so when we update information for an adult we should check for guarantees and update the relevant part
+ # of their records, ie addresses and phone numbers
+ if ($data{'categorycode'} eq 'A' || $data{'categorycode'} eq 'W'){
+ # is adult check guarantees;
+ updateguarantees(%data);
+ }
+}
+
+sub newmember {
+ my (%data) = @_;
+ my $dbh = C4::Context->dbh;
+ $data{'dateofbirth'}=format_date_in_iso($data{'dateofbirth'});
+
+
+ if ($data{'joining'}){
+ $data{'joining'}=format_date_in_iso($data{'joining'});
+ }else{
+ $data{'joining'} = get_today();
+ }
+ # if expirydate is not set, calculate it from borrower category subscription duration
+ if ($data{'expiry'}) {
+ $data{'expiry'}=format_date_in_iso($data{'expiry'});
+ }else{
+
+ $data{'expiry'} = calcexpirydate($data{'categorycode'},$data{'joining'});
+ }
+
+ my $query= "INSERT INTO borrowers (
+ cardnumber,
+ surname,
+ firstname,
+ title,
+ initials,
+ dateofbirth,
+ sex,
+ streetaddress,
+ streetcity,
+ zipcode,
+ phoneday,
+ physstreet,
+ city,
+ homezipcode,
+ phone,
+ emailaddress,
+ faxnumber,
+ textmessaging,
+ preferredcont,
+ categorycode,
+ branchcode,
+ borrowernotes,
+ ethnicity,
+ ethnotes,
+ expiry,
+ dateenrolled,
+ sort1,
+ sort2
+ )
+ VALUES (
+ '$data{'cardnumber'}',
+ '$data{'surname'}',
+ '$data{'firstname'}',
+ '$data{'title'}',
+ '$data{'initials'}',
+ '$data{'dateofbirth'}',
+ '$data{'sex'}',
+
+ '$data{'streetaddress'}',
+ '$data{'streetcity'}',
+ '$data{'zipcode'}',
+ '$data{'phoneday'}',
+
+ '$data{'physstreet'}',
+ '$data{'city'}',
+ '$data{'homezipcode'}',
+ '$data{'phone'}',
+
+ '$data{'emailaddress'}',
+ '$data{'faxnumber'}',
+ '$data{'textmessaging'}',
+ '$data{'preferredcont'}',
+ '$data{'categorycode'}',
+ '$data{'branchcode'}',
+ '$data{'borrowernotes'}',
+ '$data{'ethnicity'}',
+ '$data{'ethnotes'}',
+ '$data{'expiry'}',
+ '$data{'joining'}',
+ '$data{'sort1'}',
+ '$data{'sort2'}'
+ )";
+ my $sth=$dbh->prepare($query);
+ $sth->execute;
+ $sth->finish;
+ $data{'bornum'} =$dbh->{'mysql_insertid'};
+ return $data{'bornum'};
+}
+
+sub calcexpirydate {
+ my ( $categorycode, $dateenrolled ) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth =
+ $dbh->prepare(
+ "select enrolmentperiod from categories where categorycode=?");
+ $sth->execute($categorycode);
+ my ($enrolmentperiod) = $sth->fetchrow;
+$enrolmentperiod = 1 unless ($enrolmentperiod);#enrolmentperiod in years
+ my $duration=get_duration($enrolmentperiod." years");
+ return DATE_Add_Duration($dateenrolled,$duration);
+
+}
+
+=head2 checkuserpassword (OUEST-PROVENCE)
+
+check for the password and login are not used
+return the number of record
+0=> NOT USED 1=> USED
+
+=cut
+
+sub checkuserpassword {
+ my ( $borrowernumber, $userid, $password ) = @_;
+ $password = md5_base64($password);
+ my $dbh = C4::Context->dbh;
+ my $sth =
+ $dbh->prepare(
+"Select count(*) from borrowers where borrowernumber !=? and userid =? and password=? "
+ );
+ $sth->execute( $borrowernumber, $userid, $password );
+ my $number_rows = $sth->fetchrow;
+ return $number_rows;
+
+}
+sub getmemberfromuserid {
+ my ($userid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("select * from borrowers where userid=?");
+ $sth->execute($userid);
+ return $sth->fetchrow_hashref;
+}
+sub updateguarantees {
+ my (%data) = @_;
+ my $dbh = C4::Context->dbh;
+ my ( $count, $guarantees ) = findguarantees( $data{'borrowernumber'} );
+ for ( my $i = 0 ; $i < $count ; $i++ ) {
+
+ # FIXME
+ # It looks like the $i is only being returned to handle walking through
+ # the array, which is probably better done as a foreach loop.
+ #
+ my $guaquery =
+"update borrowers set streetaddress='$data{'address'}',faxnumber='$data{'faxnumber'}',
+ streetcity='$data{'streetcity'}',phoneday='$data{'phoneday'}',city='$data{'city'}',area='$data{'area'}',phone='$data{'phone'}'
+ ,streetaddress='$data{'address'}'
+ where borrowernumber='$guarantees->[$i]->{'borrowernumber'}'";
+ my $sth3 = $dbh->prepare($guaquery);
+ $sth3->execute;
+ $sth3->finish;
+ }
+}
+################################################################################
+
+=item fixup_cardnumber
+
+Warning: The caller is responsible for locking the members table in write
+mode, to avoid database corruption.
+
+=cut
+
+use vars qw( @weightings );
+my @weightings = ( 8, 4, 6, 3, 5, 2, 1 );
+
+sub fixup_cardnumber {
+ my ($cardnumber) = @_;
+ my $autonumber_members = C4::Context->boolean_preference('autoMemberNum');
+ $autonumber_members = 0 unless defined $autonumber_members;
+my $rem;
+ # Find out whether member numbers should be generated
+ # automatically. Should be either "1" or something else.
+ # Defaults to "0", which is interpreted as "no".
+
+ # if ($cardnumber !~ /\S/ && $autonumber_members) {
+ if ($autonumber_members) {
+ my $dbh = C4::Context->dbh;
+ if ( C4::Context->preference('checkdigit') eq 'katipo' ) {
+
+ # if checkdigit is selected, calculate katipo-style cardnumber.
+ # otherwise, just use the max()
+ # purpose: generate checksum'd member numbers.
+ # We'll assume we just got the max value of digits 2-8 of member #'s
+ # from the database and our job is to increment that by one,
+ # determine the 1st and 9th digits and return the full string.
+ my $sth =
+ $dbh->prepare(
+ "select max(substring(borrowers.cardnumber,2,7)) from borrowers"
+ );
+ $sth->execute;
+
+ my $data = $sth->fetchrow_hashref;
+ $cardnumber = $data->{'max(substring(borrowers.cardnumber,2,7))'};
+ $sth->finish;
+
+ if ( !$cardnumber ) { # If DB has no values,
+ $cardnumber = 1000000; # start at 1000000
+ } else {
+ $cardnumber += 1;
+ }
+
+ my $sum = 0;
+ for ( my $i = 0 ; $i < 8 ; $i += 1 ) {
+
+ # read weightings, left to right, 1 char at a time
+ my $temp1 = $weightings[$i];
+
+ # sequence left to right, 1 char at a time
+ my $temp2 = substr( $cardnumber, $i, 1 );
+
+ # mult each char 1-7 by its corresponding weighting
+ $sum += $temp1 * $temp2;
+ }
+
+ $rem = ( $sum % 11 );
+ $rem = 'X' if $rem == 10;
+
+ $cardnumber = "V$cardnumber$rem";
+ }
+ else {
+
+ # MODIFIED BY JF: mysql4.1 allows casting as an integer, which is probably
+ # better. I'll leave the original in in case it needs to be changed for you
+ my $sth =
+ $dbh->prepare(
+ "select max(cast(cardnumber as signed)) from borrowers");
+
+ #my $sth=$dbh->prepare("select max(borrowers.cardnumber) from borrowers");
+
+ $sth->execute;
+
+ $cardnumber="V$cardnumber$rem";
+ }
+ return $cardnumber;
+}
+}
+sub fixupneu_cardnumber{
+ my($cardnumber,$categorycode) = @_;
+ my $autonumber_members = C4::Context->boolean_preference('autoMemberNum');
+ $autonumber_members = 0 unless defined $autonumber_members;
+ # Find out whether member numbers should be generated
+ # automatically. Should be either "1" or something else.
+ # Defaults to "0", which is interpreted as "no".
+my $dbh = C4::Context->dbh;
+my $sth;
+ if (!$cardnumber && $autonumber_members && $categorycode) {
+ if ($categorycode eq "A" || $categorycode eq "W" ){
+ $sth=$dbh->prepare("select max(borrowers.cardnumber) from borrowers where borrowers.cardnumber like '5%' ");
+ }elsif ($categorycode eq "L"){
+ $sth=$dbh->prepare("select max(borrowers.cardnumber) from borrowers where borrowers.cardnumber like '10%' ");
+ }elsif ($categorycode eq "F" || $categorycode eq "E") {
+ $sth=$dbh->prepare("select max(borrowers.cardnumber) from borrowers where borrowers.cardnumber like '30%' ");
+ }elsif ($categorycode eq "N"){
+ $sth=$dbh->prepare("select max(borrowers.cardnumber) from borrowers where borrowers.cardnumber like '40%' ");
+ }elsif ($categorycode eq "C"){
+ $sth=$dbh->prepare("select max(borrowers.cardnumber) from borrowers where borrowers.cardnumber like '80%' ");
+
+ }else{
+ $sth=$dbh->prepare("select max(borrowers.cardnumber) from borrowers where borrowers.cardnumber like '6%' ");
+ }
+ $sth->execute;
+
+ my $data=$sth->fetchrow_hashref;
+ $cardnumber=$data->{'max(borrowers.cardnumber)'};
+ $sth->finish;
+
+ # purpose: generate checksum'd member numbers.
+ # We'll assume we just got the max value of digits 2-8 of member #'s
+ # from the database and our job is to increment that by one,
+ # determine the 1st and 9th digits and return the full string.
+
+ if (! $cardnumber) { # If DB has no values,
+ if ($categorycode eq "A" || $categorycode eq "W" ){ $cardnumber = 5000000;}
+ elsif ($categorycode eq "L"){ $cardnumber = 1000000;}
+ elsif ($categorycode eq "F"){ $cardnumber = 3000000;}
+ elsif ($categorycode eq "C"){ $cardnumber = 8000000;}
+ elsif ($categorycode eq "N"){ $cardnumber = 4000000;}
+ else{$cardnumber = 6000000;}
+ # start at 1000000 or 3000000 or 5000000
+ } else {
+ $cardnumber += 1;
+ }
+
+
+ }
+ return $cardnumber;
+}
+
+=item GuarantornameSearch
+
+ ($count, $borrowers) = &GuarantornameSearch($env, $searchstring, $type);
+
+Looks up guarantor by name.
+
+C<$env> is ignored.
+
+BUGFIX 499: C<$type> is now used to determine type of search.
+if $type is "simple", search is performed on the first letter of the
+surname only.
+
+C<$searchstring> is a space-separated list of search terms. Each term
+must match the beginning a borrower's surname, first name, or other
+name.
+
+C<&GuarantornameSearch> returns a two-element list. C<$borrowers> is a
+reference-to-array; each element is a reference-to-hash, whose keys
+are the fields of the C<borrowers> table in the Koha database.
+C<$count> is the number of elements in C<$borrowers>.
+
+return all info from guarantor =>only category_type A
+
+=cut
+
+#'
+#used by member enquiries from the intranet
+#called by guarantor_search.pl
+sub GuarantornameSearch {
+ my ( $env, $searchstring, $orderby, $type ) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = "";
+ my $count;
+ my @data;
+ my @bind = ();
+
+ if ( $type eq "simple" ) # simple search for one letter only
+ {
+ $query =
+"Select * from borrowers,categories where borrowers.categorycode=categories.categorycode and category_type='A' and surname like ? order by $orderby";
+ @bind = ("$searchstring%");
+ }
+ else # advanced search looking in surname, firstname and othernames
+ {
+ @data = split( ' ', $searchstring );
+ $count = @data;
+ $query = "Select * from borrowers,categories
+ where ((surname like ? or surname like ?
+ or firstname like ? or firstname like ?
+ or othernames like ? or othernames like ?) and borrowers.categorycode=categories.categorycode and category_type='A'
+ ";
+ @bind = (
+ "$data[0]%", "% $data[0]%", "$data[0]%", "% $data[0]%",
+ "$data[0]%", "% $data[0]%"
+ );
+ for ( my $i = 1 ; $i < $count ; $i++ ) {
+ $query = $query . " and (" . " surname like ? or surname like ?
+ or firstname like ? or firstname like ?
+ or othernames like ? or othernames like ?)";
+ push( @bind,
+ "$data[$i]%", "% $data[$i]%", "$data[$i]%",
+ "% $data[$i]%", "$data[$i]%", "% $data[$i]%" );
+
+ # FIXME - .= <<EOT;
+ }
+ $query = $query . ") or cardnumber like ?
+ order by $orderby";
+ push( @bind, $searchstring );
+
+ # FIXME - .= <<EOT;
+ }
+
+ my $sth = $dbh->prepare($query);
+ $sth->execute(@bind);
+ my @results;
+ my $cnt = $sth->rows;
+ while ( my $data = $sth->fetchrow_hashref ) {
+ push( @results, $data );
+ }
+
+ # $sth->execute;
+ $sth->finish;
+ return ( $cnt, \@results );
+}
+
+
+=item findguarantees
+
+ ($num_children, $children_arrayref) = &findguarantees($parent_borrno);
+ $child0_cardno = $children_arrayref->[0]{"cardnumber"};
+ $child0_borrno = $children_arrayref->[0]{"borrowernumber"};
+
+C<&findguarantees> takes a borrower number (e.g., that of a patron
+with children) and looks up the borrowers who are guaranteed by that
+borrower (i.e., the patron's children).
+
+C<&findguarantees> returns two values: an integer giving the number of
+borrowers guaranteed by C<$parent_borrno>, and a reference to an array
+of references to hash, which gives the actual results.
+
+=cut
+#'
+sub findguarantees{
+ my ($bornum)=@_;
+ my $dbh = C4::Context->dbh;
+ my $sth=$dbh->prepare("select cardnumber,borrowernumber, firstname, surname from borrowers where guarantor=?");
+ $sth->execute($bornum);
+
+ my @dat;
+ while (my $data = $sth->fetchrow_hashref)
+ {
+ push @dat, $data;
+ }
+ $sth->finish;
+ return (scalar(@dat), \@dat);
+}
+
+=item findguarantor
+
+ $guarantor = &findguarantor($borrower_no);
+ $guarantor_cardno = $guarantor->{"cardnumber"};
+ $guarantor_surname = $guarantor->{"surname"};
+ ...
+
+C<&findguarantor> takes a borrower number (presumably that of a child
+patron), finds the guarantor for C<$borrower_no> (the child's parent),
+and returns the record for the guarantor.
+
+C<&findguarantor> returns a reference-to-hash. Its keys are the fields
+from the C<borrowers> database table;
+
+=cut
+#'
+sub findguarantor{
+ my ($bornum)=@_;
+ my $dbh = C4::Context->dbh;
+ my $sth=$dbh->prepare("select guarantor from borrowers where borrowernumber=?");
+ $sth->execute($bornum);
+ my $data=$sth->fetchrow_hashref;
+ $sth->finish;
+ $sth=$dbh->prepare("Select * from borrowers where borrowernumber=?");
+ $sth->execute($data->{'guarantor'});
+ $data=$sth->fetchrow_hashref;
+ $sth->finish;
+ return($data);
+}
+
+sub borrowercard_active {
+ my ($bornum) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("SELECT expiry FROM borrowers WHERE (borrowernumber = ?) AND (NOW() <= expiry)");
+ $sth->execute($bornum);
+ if (my $data=$sth->fetchrow_hashref){
+ return ('1');
+ }else{
+ return ('0');
+ }
+}
+
+# Search the member photo, in case that photo doesn´t exists, return a default photo.for NEU
+sub getMemberPhoto {
+ my $cardnumber = shift @_;
+ my $htdocs = C4::Context->config('opacdir');
+my $dirname = $htdocs."/htdocs/uploaded-files/users-photo/";
+# my $dirname = "$ENV{'DOCUMENT_ROOT'}/uploaded-files/users-photo";
+ opendir(DIR, $dirname) or die "Can't open directory $dirname: $!";
+ while (defined(my $file = readdir(DIR))) {
+ if ($file =~ /^$cardnumber\..+/){
+ return "/uploaded-files/users-photo/$file";
+ }
+ }
+ closedir(DIR);
+ return "http://cc.neu.edu.tr/stdpictures/".$cardnumber.".jpg";
+}
+
+sub change_user_pass {
+ my ($uid,$member,$digest) = @_;
+ my $dbh = C4::Context->dbh;
+ #Make sure the userid chosen is unique and not theirs if non-empty. If it is not,
+ #Then we need to tell the user and have them create a new one.
+ my $sth=$dbh->prepare("select * from borrowers where userid=? and borrowernumber <> ?");
+ $sth->execute($uid,$member);
+ if ( ($uid ne '') && ($sth->fetchrow) ) {
+
+ return 0;
+ } else {
+ #Everything is good so we can update the information.
+ $sth=$dbh->prepare("update borrowers set userid=?, password=? where borrowernumber=?");
+ $sth->execute($uid, $digest, $member);
+ return 1;
+ }
+
+}
+
+=head2 checkuniquemember (OUEST-PROVENCE)
+
+ $result = &checkuniquemember($collectivity,$surname,$categorycode,$firstname,$dateofbirth);
+
+Checks that a member exists or not in the database.
+
+C<&result> is 1 (=exist) or 0 (=does not exist)
+C<&collectivity> is 1 (= we add a collectivity) or 0 (= we add a physical member)
+C<&surname> is the surname
+C<&categorycode> is from categorycode table
+C<&firstname> is the firstname (only if collectivity=0)
+C<&dateofbirth> is the date of birth (only if collectivity=0)
+
+=cut
+sub checkuniquemember {
+ my ( $collectivity, $surname, $firstname, $dateofbirth ) = @_;
+ my $dbh = C4::Context->dbh;
+ my $request;
+ if ($collectivity) {
+
+# $request="select count(*) from borrowers where surname=? and categorycode=?";
+ $request =
+ "select borrowernumber,categorycode from borrowers where surname=? ";
+ }
+ else {
+
+# $request="select count(*) from borrowers where surname=? and categorycode=? and firstname=? and dateofbirth=?";
+ $request =
+"select borrowernumber,categorycode from borrowers where surname=? and firstname=? and dateofbirth=?";
+ }
+ my $sth = $dbh->prepare($request);
+ if ($collectivity) {
+ $sth->execute( uc($surname) );
+ }
+ else {
+ $sth->execute( uc($surname), ucfirst($firstname), $dateofbirth );
+ }
+ my @data = $sth->fetchrow;
+ if ( $data[0] ) {
+ $sth->finish;
+ return $data[0], $data[1];
+
+ #
+ }
+ else {
+ $sth->finish;
+ return 0;
+ }
+}
+=head2 getzipnamecity (OUEST-PROVENCE)
+
+take all info from table city for the fields city and zip
+check for the name and the zip code of the city selected
+
+=cut
+
+sub getzipnamecity {
+ my ($cityid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth =
+ $dbh->prepare(
+ "select city_name,city_zipcode from cities where cityid=? ");
+ $sth->execute($cityid);
+ my @data = $sth->fetchrow;
+ return $data[0], $data[1];
+}
+
+=head2 updatechildguarantor (OUEST-PROVENCE)
+
+check for title,firstname,surname,adress,zip code and city from guarantor to
+guarantorchild
+
+=cut
+
+#'
+
+sub getguarantordata {
+ my ($borrowerid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth =
+ $dbh->prepare(
+"Select title,firstname,surname,streetnumber,address,streettype,address2,zipcode,city,phone,phonepro,mobile,email,emailpro,fax from borrowers where borrowernumber =? "
+ );
+ $sth->execute($borrowerid);
+ my $guarantor_data = $sth->fetchrow_hashref;
+ $sth->finish;
+ return $guarantor_data;
+}
+
+=head2 getdcity (OUEST-PROVENCE)
+recover cityid with city_name condition
+=cut
+
+sub getidcity {
+ my ($city_name) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("select cityid from cities where city_name=? ");
+ $sth->execute($city_name);
+ my $data = $sth->fetchrow;
+ return $data;
+}
+
+=head2 getcategorytype (OUEST-PROVENCE)
+
+check for the category_type with categorycode
+and return the category_type
+
+=cut
+
+sub getcategorytype {
+ my ($categorycode) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth =
+ $dbh->prepare(
+"Select category_type,description from categories where categorycode=? "
+ );
+ $sth->execute($categorycode);
+ my ( $category_type, $description ) = $sth->fetchrow;
+ return $category_type, $description;
+}
+
+
+
+
+
+
+
+# # A better approach might be to set borrowernumber autoincrement and
+#
+ sub NewBorrowerNumber {
+ my $dbh = C4::Context->dbh;
+ my $sth=$dbh->prepare("Select max(borrowernumber) from borrowers");
+ $sth->execute;
+ my $data=$sth->fetchrow_hashref;
+ $sth->finish;
+ $data->{'max(borrowernumber)'}++;
+ return($data->{'max(borrowernumber)'});
+ }
+
+=head2 ethnicitycategories
+
+ ($codes_arrayref, $labels_hashref) = ðnicitycategories();
+
+Looks up the different ethnic types in the database. Returns two
+elements: a reference-to-array, which lists the ethnicity codes, and a
+reference-to-hash, which maps the ethnicity codes to ethnicity
+descriptions.
+
+=cut
+
+#'
+
+sub ethnicitycategories {
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("Select code,name from ethnicity order by name");
+ $sth->execute;
+ my %labels;
+ my @codes;
+ while ( my $data = $sth->fetchrow_hashref ) {
+ push @codes, $data->{'code'};
+ $labels{ $data->{'code'} } = $data->{'name'};
+ }
+ $sth->finish;
+ return ( \@codes, \%labels );
+}
+
+=head2 fixEthnicity
+
+ $ethn_name = &fixEthnicity($ethn_code);
+
+Takes an ethnicity code (e.g., "european" or "pi") and returns the
+corresponding descriptive name from the C<ethnicity> table in the
+Koha database ("European" or "Pacific Islander").
+
+=cut
+
+#'
+
+sub fixEthnicity{
+
+ my $ethnicity = shift;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("Select name from ethnicity where code = ?");
+ $sth->execute($ethnicity);
+ my $data = $sth->fetchrow_hashref;
+ $sth->finish;
+ return $data->{'name'};
+} # sub fixEthnicity
+
+
+
+=head2 get_age
+
+ $dateofbirth,$date = &get_age($date);
+
+this function return the borrowers age with the value of dateofbirth
+
+=cut
+#'
+sub get_age {
+ my ($date, $date_ref) = @_;
+
+ if (not defined $date_ref) {
+ $date_ref = get_today();
+ }
+
+ my ($year1, $month1, $day1) = split /-/, $date;
+ my ($year2, $month2, $day2) = split /-/, $date_ref;
+
+ my $age = $year2 - $year1;
+ if ($month1.$day1 > $month2.$day2) {
+ $age--;
+ }
+
+ return $age;
+}# sub get_age
+
+
+
+=head2 get_institutions
+ $insitutions = get_institutions();
+
+Just returns a list of all the borrowers of type I, borrownumber and name
+=cut
+
+#'
+sub get_institutions {
+ my $dbh = C4::Context->dbh();
+ my $sth =
+ $dbh->prepare(
+"SELECT borrowernumber,surname FROM borrowers WHERE categorycode=? ORDER BY surname"
+ );
+ $sth->execute('I');
+ my %orgs;
+ while ( my $data = $sth->fetchrow_hashref() ) {
+ $orgs{ $data->{'borrowernumber'} } = $data;
+ }
+ $sth->finish();
+ return ( \%orgs );
+
+} # sub get_institutions
+
+=head2 add_member_orgs
+
+ add_member_orgs($borrowernumber,$borrowernumbers);
+
+Takes a borrowernumber and a list of other borrowernumbers and inserts them into the borrowers_to_borrowers table
+
+=cut
+
+#'
+sub add_member_orgs {
+ my ( $borrowernumber, $otherborrowers ) = @_;
+ my $dbh = C4::Context->dbh();
+ my $query =
+ "INSERT INTO borrowers_to_borrowers (borrower1,borrower2) VALUES (?,?)";
+ my $sth = $dbh->prepare($query);
+ foreach my $bornum (@$otherborrowers) {
+ $sth->execute( $borrowernumber, $bornum );
+ }
+ $sth->finish();
+
+} # sub add_member_orgs
+
+=head2 GetBorrowersFromSurname
+
+=over 4
+
+\@resutlts = GetBorrowersFromSurname($surname)
+this function get the list of borrower names like $surname.
+return :
+the table of results in @results
+
+=back
+
+=cut
+sub GetBorrowersFromSurname {
+ my ($searchstring)=@_;
+ my $dbh = C4::Context->dbh;
+ $searchstring=~ s/\'/\\\'/g;
+ my @data=split(' ',$searchstring);
+ my $count=@data;
+ my $query = qq|
+ SELECT surname,firstname
+ FROM borrowers
+ WHERE (surname like ?)
+ ORDER BY surname
+ |;
+ my $sth=$dbh->prepare($query);
+ $sth->execute("$data[0]%");
+ my @results;
+ my $count = 0;
+ while (my $data=$sth->fetchrow_hashref){
+ push(@results,$data);
+ $count++;
+ }
+ $sth->finish;
+ return ($count,\@results);
+}
+
+=head2 expand_sex_into_predicate
+
+ $data{&expand_sex_into_predicate($data{sex})} = 1;
+
+Converts a single 'M' or 'F' into 'sex_M_p' or 'sex_F_p'
+respectively.
+
+In some languages, 'M' and 'F' are not appropriate. However,
+with HTML::Template, there is no way to localize 'M' or 'F'
+unless these are converted into variables that TMPL_IF can
+understand. This function provides this conversion.
+
+=cut
+
+sub expand_sex_into_predicate {
+ my($sex) = @_;
+ return "sex_${sex}_p";
+} # expand_sex_into_predicate
+
+
+#
+# NOTE!: If you change this function, be sure to update the POD for
+# &getpatroninformation.
+#
+# $flags = &patronflags($env, $patron, $dbh);
+#
+# $flags->{CHARGES}
+# {message} Message showing patron's credit or debt
+# {noissues} Set if patron owes >$5.00
+# {GNA} Set if patron gone w/o address
+# {message} "Borrower has no valid address"
+# {noissues} Set.
+# {LOST} Set if patron's card reported lost
+# {message} Message to this effect
+# {noissues} Set.
+# {DBARRED} Set is patron is debarred
+# {message} Message to this effect
+# {noissues} Set.
+# {NOTES} Set if patron has notes
+# {message} Notes about patron
+# {ODUES} Set if patron has overdue books
+# {message} "Yes"
+# {itemlist} ref-to-array: list of overdue books
+# {itemlisttext} Text list of overdue items
+# {WAITING} Set if there are items available that the
+# patron reserved
+# {message} Message to this effect
+# {itemlist} ref-to-array: list of available items
+sub patronflags {
+# Original subroutine for Circ2.pm
+ my %flags;
+ my ($env, $patroninformation, $dbh) = @_;
+ my $amount = C4::Accounts2::checkaccount($env, $patroninformation->{'borrowernumber'}, $dbh);
+ if ($amount > 0) {
+ my %flaginfo;
+ my $noissuescharge = C4::Context->preference("noissuescharge");
+ $flaginfo{'message'}= sprintf "Patron owes \$%.02f", $amount;
+ if ($amount > $noissuescharge) {
+ $flaginfo{'noissues'} = 1;
+ }
+ $flags{'CHARGES'} = \%flaginfo;
+ } elsif ($amount < 0){
+ my %flaginfo;
+ $flaginfo{'message'} = sprintf "Patron has credit of \$%.02f", -$amount;
+ $flags{'CHARGES'} = \%flaginfo;
+ }
+ if ($patroninformation->{'gonenoaddress'} == 1) {
+ my %flaginfo;
+ $flaginfo{'message'} = 'Borrower has no valid address.';
+ $flaginfo{'noissues'} = 1;
+ $flags{'GNA'} = \%flaginfo;
+ }
+ if ($patroninformation->{'lost'} == 1) {
+ my %flaginfo;
+ $flaginfo{'message'} = 'Borrower\'s card reported lost.';
+ $flaginfo{'noissues'} = 1;
+ $flags{'LOST'} = \%flaginfo;
+ }
+ if ($patroninformation->{'debarred'} == 1) {
+ my %flaginfo;
+ $flaginfo{'message'} = 'Borrower is Debarred.';
+ $flaginfo{'noissues'} = 1;
+ $flags{'DBARRED'} = \%flaginfo;
+ }
+ if ($patroninformation->{'borrowernotes'}) {
+ my %flaginfo;
+ $flaginfo{'message'} = "$patroninformation->{'borrowernotes'}";
+ $flags{'NOTES'} = \%flaginfo;
+ }
+ my ($odues, $itemsoverdue)
+ = checkoverdues($env, $patroninformation->{'borrowernumber'}, $dbh);
+ if ($odues > 0) {
+ my %flaginfo;
+ $flaginfo{'message'} = "Yes";
+ $flaginfo{'itemlist'} = $itemsoverdue;
+ foreach (sort {$a->{'date_due'} cmp $b->{'date_due'}} @$itemsoverdue) {
+ $flaginfo{'itemlisttext'}.="$_->{'date_due'} $_->{'barcode'} $_->{'title'} \n";
+ }
+ $flags{'ODUES'} = \%flaginfo;
+ }
+ my ($nowaiting, $itemswaiting)=C4::Reserves2::CheckWaiting($patroninformation->{'borrowernumber'});
+ if ($nowaiting > 0) {
+ my %flaginfo;
+ $flaginfo{'message'} = "Reserved items available";
+ $flaginfo{'itemlist'} = $itemswaiting;
+ $flags{'WAITING'} = \%flaginfo;
+ }
+ return(\%flags);
+}
+
+##Not exported same in Circ2
+sub checkoverdues {
+# From Circ2.pm, added here to prevent recursive inclusion of Circ2
+ #checks whether a borrower has overdue items
+ my ($env, $bornum, $dbh)=@_;
+ my $today=get_today();
+ my @overdueitems;
+ my $count = 0;
+ my $sth = $dbh->prepare("SELECT issues.* , i.biblionumber as biblionumber,b.* FROM issues, items i,biblio b
+ WHERE i.itemnumber=issues.itemnumber
+ AND i.biblionumber=b.biblionumber
+ AND issues.borrowernumber = ?
+ AND issues.returndate is NULL
+ AND issues.date_due < ?");
+ $sth->execute($bornum,$today);
+ while (my $data = $sth->fetchrow_hashref) {
+
+ push (@overdueitems, $data);
+ $count++;
+ }
+ $sth->finish;
+ return ($count, \@overdueitems);
+}
+1;
+__END__
\ No newline at end of file
Index: NewsChannels.pm
===================================================================
RCS file: NewsChannels.pm
diff -N NewsChannels.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ NewsChannels.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,388 @@
+package C4::NewsChannels;
+
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+require Exporter;
+use C4::Context;
+use C4::Date;
+
+use vars qw($VERSION @ISA @EXPORT);
+
+# set the version for version checking
+$VERSION = 0.01;
+
+=head1 NAME
+
+C4::NewsChannels - Functions to manage the news channels and its categories
+
+=head1 DESCRIPTION
+
+This module provides the functions needed to admin the news channels and its categories
+
+=head1 FUNCTIONS
+
+=over 2
+
+=cut
+
+
+ at ISA = qw(Exporter);
+ at EXPORT = qw(
+ &news_channels &get_new_channel &del_channels &add_channel &update_channel
+ &news_channels_categories &get_new_channel_category &del_channels_categories
+ &add_channel_category &update_channel_category &news_channels_by_category
+&add_opac_new &upd_opac_new &del_opac_new &get_opac_new &get_opac_news
+ &add_opac_electronic &upd_opac_electronic &del_opac_electronic &get_opac_electronic &get_opac_electronics
+);
+
+
+=item news_channels
+
+ ($count, @channels) = &news_channels($channel_name, $id_category, $unclassified);
+
+Looks up news channels by name or category.
+
+C<$channel_name> is the channel name to search.
+
+C<$id_category> is the channel category code to search.
+
+C<$$unclassified> if it is set and $channel_name and $id_category search for the news channels without a category
+
+if none of the params are set C<&news_channels> returns all the news channels.
+
+C<&news_channels> returns two values: an integer giving the number of
+news channels found and a reference to an array
+of references to hash, which has the news_channels and news_channels_categories fields.
+
+=cut
+
+sub news_channels {
+ my ($channel_name, $id_category, $unclassified) = @_;
+ my $dbh = C4::Context->dbh;
+ my @channels;
+ my $query = "SELECT * FROM news_channels LEFT JOIN news_channels_categories ON news_channels.id_category = news_channels_categories.id_category";
+ if ( ($channel_name ne '') && ($id_category ne '') ) {
+ $query.= " WHERE channel_name like '" . $channel_name . "%' AND news_channels.id_category = " . $id_category;
+ } elsif ($channel_name ne '') {
+ $query.= " WHERE channel_name like '" . $channel_name . "%'";
+ } elsif ($id_category ne '') {
+ $query.= " WHERE news_channels.id_category = " . $id_category;
+ } elsif ($unclassified) {
+ $query.= " WHERE news_channels.id_category IS NULL ";
+ }
+ my $sth = $dbh->prepare($query);
+ $sth->execute();
+ while (my $row = $sth->fetchrow_hashref) {
+ push @channels, $row;
+ }
+ $sth->finish;
+ return (scalar(@channels), @channels);
+}
+
+=item news_channels_by_category
+
+ ($count, @results) = &news_channels_by_category();
+
+Looks up news channels grouped by category.
+
+C<&news_channels_by_category> returns two values: an integer giving the number of
+categories found and a reference to an array
+of references to hash, which the following keys:
+
+=over 4
+
+=item C<channels_count>
+
+The number of news channels in that category
+
+=item C<channels>
+
+A reference to an array of references to hash which keys are the new_channels fields.
+
+Additionally the last index of results has a reference to all the news channels which don't have a category
+
+=cut
+
+sub news_channels_by_category {
+
+ my ($categories_count, @results) = &news_channels_categories();
+ foreach my $row (@results) {
+
+ my ($channels_count, @channels) = &news_channels('', $row->{'id_category'});
+ $row->{'channels_count'} = $channels_count;
+ $row->{'channels'} = \@channels;
+ }
+
+ my ($channels_count, @channels) = &news_channels('', '', 1);
+ my %row;
+ $row{'id_category'} = -1;
+ $row{'unclassified'} = 1;
+ $row{'channels_count'} = $channels_count;
+ $row{'channels'} = \@channels;
+ push @results, \%row;
+
+ return (scalar(@results), @results);
+}
+
+sub get_new_channel {
+ my ($id) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("SELECT * FROM news_channels WHERE id = ?");
+ $sth->execute($id);
+ my $channel = $sth->fetchrow_hashref;
+ $sth->finish;
+ return $channel;
+}
+
+sub del_channels {
+ my ($ids) = @_;
+ if ($ids ne '') {
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("DELETE FROM news_channels WHERE id IN ($ids) ");
+ $sth->execute();
+ $sth->finish;
+ return $ids;
+ }
+ return 0;
+}
+
+sub add_channel {
+ my ($name, $url, $id_category, $notes) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("INSERT INTO news_channels (channel_name, url, id_category, notes) VALUES (?,?,?,?)");
+ $sth->execute($name, $url, $id_category, $notes);
+ $sth->finish;
+ return 1;
+}
+
+sub update_channel {
+ my ($id, $name, $url, $id_category, $notes) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("UPDATE news_channels SET channel_name = ?, url = ?, id_category = ?, notes = ? WHERE id = ?");
+ $sth->execute($name, $url, $id_category, $notes, $id);
+ $sth->finish;
+ return 1;
+}
+
+sub news_channels_categories {
+ my $dbh = C4::Context->dbh;
+ my @categories;
+ my $query = "SELECT * FROM news_channels_categories";
+ my $sth = $dbh->prepare($query);
+ $sth->execute();
+ while (my $row = $sth->fetchrow_hashref) {
+ push @categories, $row;
+ }
+ $sth->finish;
+ return (scalar(@categories), @categories);
+
+}
+
+sub get_new_channel_category {
+ my ($id) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("SELECT * FROM news_channels_categories WHERE id_category = ?");
+ $sth->execute($id);
+ my $category = $sth->fetchrow_hashref;
+ $sth->finish;
+ return $category;
+}
+
+sub del_channels_categories {
+ my ($ids) = @_;
+ if ($ids ne '') {
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("UPDATE news_channels SET id_category = NULL WHERE id_category IN ($ids) ");
+ $sth->execute();
+ $sth = $dbh->prepare("DELETE FROM news_channels_categories WHERE id_category IN ($ids) ");
+ $sth->execute();
+ $sth->finish;
+ return $ids;
+ }
+ return 0;
+}
+
+sub add_channel_category {
+ my ($name) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("INSERT INTO news_channels_categories (category_name) VALUES (?)");
+ $sth->execute($name);
+ $sth->finish;
+ return 1;
+}
+
+sub update_channel_category {
+ my ($id, $name) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("UPDATE news_channels_categories SET category_name = ? WHERE id_category = ?");
+ $sth->execute($name, $id);
+ $sth->finish;
+ return 1;
+}
+
+
+sub add_opac_new {
+ my ($title, $new, $lang) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("INSERT INTO opac_news (title, new, lang) VALUES (?,?,?)");
+ $sth->execute($title, $new, $lang);
+ $sth->finish;
+ return 1;
+}
+
+sub upd_opac_new {
+ my ($idnew, $title, $new, $lang) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("UPDATE opac_news SET title = ?, new = ?, lang = ? WHERE idnew = ?");
+ $sth->execute($title, $new, $lang, $idnew);
+ $sth->finish;
+ return 1;
+}
+
+sub del_opac_new {
+ my ($ids) = @_;
+ if ($ids) {
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("DELETE FROM opac_news WHERE idnew IN ($ids)");
+ $sth->execute();
+ $sth->finish;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+sub get_opac_new {
+ my ($idnew) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("SELECT * FROM opac_news WHERE idnew = ?");
+ $sth->execute($idnew);
+ my $data = $sth->fetchrow_hashref;
+ $data->{$data->{'lang'}} = 1;
+ $sth->finish;
+ return $data;
+}
+
+sub get_opac_news {
+ my ($limit, $lang) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = "SELECT *, DATE_FORMAT(timestamp,'%Y-%m-%d') AS newdate FROM opac_news";
+ if ($lang) {
+ $query.= " WHERE lang = '" .$lang ."' ";
+ }
+ $query.= " ORDER BY timestamp DESC ";
+ #if ($limit) {
+ # $query.= "LIMIT 0, " . $limit;
+ #}
+ my $sth = $dbh->prepare($query);
+ $sth->execute();
+ my @opac_news;
+ my $count = 0;
+ while (my $row = $sth->fetchrow_hashref) {
+ if ((($limit) && ($count < $limit)) || (!$limit)) {
+ $row->{'newdate'} = format_date($row->{'newdate'});
+ push @opac_news, $row;
+ }
+ $count++;
+ }
+ return ($count, \@opac_news);
+}
+
+### get electronic databases
+
+sub add_opac_electronic {
+ my ($title, $edata, $lang,$image,$href,$section) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("INSERT INTO opac_electronic (title, edata, lang,image,href,section) VALUES (?,?,?,?,?,?)");
+ $sth->execute($title, $edata, $lang,$image,$href,$section);
+ $sth->finish;
+ return 1;
+}
+
+sub upd_opac_electronic {
+ my ($idelectronic, $title, $edata, $lang, $image, $href,$section) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("UPDATE opac_electronic SET title = ?, edata = ?, lang = ? , image=?, href=? ,section=? WHERE idelectronic = ?");
+ $sth->execute($title, $edata, $lang, $image,$href ,$section, $idelectronic);
+ $sth->finish;
+ return 1;
+}
+
+sub del_opac_electronic {
+ my ($ids) = @_;
+ if ($ids) {
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("DELETE FROM opac_electronic WHERE idelectronic IN ($ids)");
+ $sth->execute();
+ $sth->finish;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+sub get_opac_electronic {
+ my ($idelectronic) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("SELECT * FROM opac_electronic WHERE idelectronic = ?");
+ $sth->execute($idelectronic);
+ my $data = $sth->fetchrow_hashref;
+ $data->{$data->{'lang'}} = 1;
+ $data->{$data->{'section'}} = 1;
+ $sth->finish;
+ return $data;
+}
+
+sub get_opac_electronics {
+ my ($section, $lang) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = "SELECT *, DATE_FORMAT(timestamp, '%Y-%m-%d') AS newdate FROM opac_electronic";
+ if ($lang) {
+ $query.= " WHERE lang = '" .$lang ."' ";
+ }
+ if ($section) {
+ $query.= " and section= '" . $section."' ";
+ }
+ $query.= " ORDER BY title ";
+
+ my $sth = $dbh->prepare($query);
+ $sth->execute();
+ my @opac_electronic;
+ my $count = 0;
+ while (my $row = $sth->fetchrow_hashref) {
+ $row->{'newdate'}=format_date($row->{'newdate'});
+ push @opac_electronic, $row;
+
+
+ $count++;
+ }
+
+ return ($count,\@opac_electronic);
+}
+1;
+__END__
+=back
+
+=head1 AUTHOR
+
+TG
+
+=cut
+
+
Index: Output.pm
===================================================================
RCS file: Output.pm
diff -N Output.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Output.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,313 @@
+package C4::Output;
+# $Id: Output.pm,v 1.1.2.1 2007/03/10 01:35:34 tgarip1957 Exp $
+
+#package to deal with marking up output
+#You will need to edit parts of this pm
+#set the value of path to be where your html lives
+
+
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+
+use strict;
+require Exporter;
+
+use C4::Context;
+use HTML::Template;
+use vars qw($VERSION @ISA @EXPORT);
+
+# set the version for version checking
+$VERSION = 0.01;
+
+=head1 NAME
+
+C4::Output - Functions for managing templates
+
+=head1 FUNCTIONS
+
+=over 2
+
+=cut
+
+ at ISA = qw(Exporter);
+ at EXPORT = qw(
+ &themelanguage &gettemplate setlanguagecookie pagination_bar
+ );
+
+#FIXME: this is a quick fix to stop rc1 installing broken
+#Still trying to figure out the correct fix.
+my $path = C4::Context->config('intrahtdocs')."/default/en/includes/";
+
+#---------------------------------------------------------------------------------------------------------
+# FIXME - POD
+sub gettemplate {
+ my ($tmplbase, $opac, $query) = @_;
+
+if (!$query){
+ warn "no query in gettemplate";
+ }
+ my $htdocs;
+ if ($opac ne "intranet") {
+ $htdocs = C4::Context->config('opachtdocs');
+ } else {
+ $htdocs = C4::Context->config('intrahtdocs');
+ }
+ my $path = C4::Context->preference('intranet_includes') || 'includes';
+# warn "PATH : $path";
+
+ my ($theme, $lang) = themelanguage($htdocs, $tmplbase, $opac, $query);
+ my $opacstylesheet = C4::Context->preference('opacstylesheet');
+
+my $template = HTML::Template->new(filename => "$htdocs/$theme/$lang/$tmplbase", case_sensitive=>1, utf8=>1,
+ die_on_bad_params => 0,
+ global_vars => 1, cache=>1,
+ path => ["$htdocs/$theme/$lang/$path"],
+ );
+
+ $template->param(themelang => ($opac ne 'intranet'? '/opac-tmpl': '/intranet-tmpl') . "/$theme/$lang",
+ interface => ($opac ne 'intranet'? '/opac-tmpl': '/intranet-tmpl'),
+ theme => $theme,
+ opacstylesheet => $opacstylesheet,
+ opaccolorstylesheet => C4::Context->preference('opaccolorstylesheet'),
+ opacsmallimage => C4::Context->preference('opacsmallimage'),
+ lang => $lang);
+
+
+ return $template;
+}
+
+#---------------------------------------------------------------------------------------------------------
+# FIXME - POD
+sub themelanguage {
+ my ($htdocs, $tmpl, $section, $query) = @_;
+# if (!$query) {
+# warn "no query";
+# }
+ my $dbh = C4::Context->dbh;
+ my @languages;
+ my @themes;
+my ($theme, $lang);
+ if ($section eq "intranet"){
+ $lang=$query->cookie('KohaOpacLanguage');
+
+ if ($lang){
+
+ push @languages,$lang;
+ @themes = split " ", C4::Context->preference("template");
+ }
+ else {
+ @languages = split " ", C4::Context->preference("opaclanguages");
+ @themes = split " ", C4::Context->preference("template");
+ }
+ }else{
+ $lang=$query->cookie('KohaOpacLanguage');
+
+ if ($lang){
+
+ push @languages,$lang;
+ @themes = split " ", C4::Context->preference("opacthemes");
+ }
+ else {
+ @languages = split " ", C4::Context->preference("opaclanguages");
+ @themes = split " ", C4::Context->preference("opacthemes");
+ }
+}
+
+
+# searches through the themes and languages. First template it find it returns.
+# Priority is for getting the theme right.
+ THEME:
+ foreach my $th (@themes) {
+ foreach my $la (@languages) {
+ for (my $pass = 1; $pass <= 2; $pass += 1) {
+ $la =~ s/([-_])/ $1 eq '-'? '_': '-' /eg if $pass == 2;
+ if (-e "$htdocs/$th/$la/$tmpl") {
+ $theme = $th;
+ $lang = $la;
+ last THEME;
+ }
+ last unless $la =~ /[-_]/;
+ }
+ }
+ }
+ if ($theme and $lang) {
+ return ($theme, $lang);
+ } else {
+ return ('default', 'en');
+ }
+}
+
+
+sub setlanguagecookie {
+ my ($query,$language,$uri)=@_;
+ my $cookie=$query->cookie(-name => 'KohaOpacLanguage',
+ -value => $language,
+ -expires => '');
+ print $query->redirect(-uri=>$uri,
+ -cookie=>$cookie);
+}
+
+=item pagination_bar
+
+ pagination_bar($base_url, $nb_pages, $current_page, $startfrom_name)
+
+Build an HTML pagination bar based on the number of page to display, the
+current page and the url to give to each page link.
+
+C<$base_url> is the URL for each page link. The
+C<$startfrom_name>=page_number is added at the end of the each URL.
+
+C<$nb_pages> is the total number of pages available.
+
+C<$current_page> is the current page number. This page number won't become a
+link.
+
+This function returns HTML, without any language dependency.
+
+=cut
+
+sub pagination_bar {
+ my ($base_url, $nb_pages, $current_page, $startfrom_name) = @_;
+
+ # how many pages to show before and after the current page?
+ my $pages_around = 2;
+
+ my $url =
+ $base_url
+ .($base_url =~ m/&/ ? '&' : '?')
+ .$startfrom_name.'='
+ ;
+
+ my $pagination_bar = '';
+
+ # current page detection
+ if (not defined $current_page) {
+ $current_page = 1;
+ }
+
+ # navigation bar useful only if more than one page to display !
+ if ($nb_pages > 1) {
+ # link to first page?
+ if ($current_page > 1) {
+ $pagination_bar.=
+ "\n".' '
+ .'<a href="'.$url.'1" rel="start">'
+ .'<<'
+ .'</a>'
+ ;
+ }
+ else {
+ $pagination_bar.=
+ "\n".' <span class="inactive"><<</span>';
+ }
+
+ # link on previous page ?
+ if ($current_page > 1) {
+ my $previous = $current_page - 1;
+
+ $pagination_bar.=
+ "\n".' '
+ .'<a href="'
+ .$url.$previous
+ .'" rel="prev">'
+ .'<'
+ .'</a>'
+ ;
+ }
+ else {
+ $pagination_bar.=
+ "\n".' <span class="inactive"><</span>';
+ }
+
+ my $min_to_display = $current_page - $pages_around;
+ my $max_to_display = $current_page + $pages_around;
+ my $last_displayed_page = undef;
+
+ for my $page_number (1..$nb_pages) {
+ if ($page_number == 1
+ or $page_number == $nb_pages
+ or ($page_number >= $min_to_display and $page_number <= $max_to_display)
+ ) {
+ if (defined $last_displayed_page
+ and $last_displayed_page != $page_number - 1
+ ) {
+ $pagination_bar.=
+ "\n".' <span class="inactive">...</span>'
+ ;
+ }
+
+ if ($page_number == $current_page) {
+ $pagination_bar.=
+ "\n".' '
+ .'<span class="currentPage">'.$page_number.'</span>'
+ ;
+ }
+ else {
+ $pagination_bar.=
+ "\n".' '
+ .'<a href="'.$url.$page_number.'">'.$page_number.'</a>'
+ ;
+ }
+ $last_displayed_page = $page_number;
+ }
+ }
+
+ # link on next page?
+ if ($current_page < $nb_pages) {
+ my $next = $current_page + 1;
+
+ $pagination_bar.=
+ "\n".' <a href="'.$url.$next.'" rel="next">'
+ .'>'
+ .'</a>'
+ ;
+ }
+ else {
+ $pagination_bar.=
+ "\n".' <span class="inactive">></span>'
+ ;
+ }
+
+ # link to last page?
+ if ($current_page != $nb_pages) {
+ $pagination_bar.=
+ "\n".' <a href="'.$url.$nb_pages.'" rel="last">'
+ .'>>'
+ .'</a>'
+ ;
+ }
+ else {
+ $pagination_bar.=
+ "\n".' <span class="inactive">>></span>';
+ }
+ }
+
+ return $pagination_bar;
+}
+
+
+1;
+__END__
+
+=back
+
+=head1 AUTHOR
+
+Koha Developement team <info at koha.org>
+
+=cut
Index: Print.pm
===================================================================
RCS file: Print.pm
diff -N Print.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Print.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,225 @@
+package C4::Print; #assumes C4/Print.pm
+
+
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+require Exporter;
+
+
+use C4::Context;
+use C4::Circulation::Circ2;
+use C4::Members;
+use vars qw($VERSION @ISA @EXPORT);
+
+# set the version for version checking
+$VERSION = 0.01;
+
+=head1 NAME
+
+C4::Print - Koha module dealing with printing
+
+=head1 SYNOPSIS
+
+ use C4::Print;
+
+=head1 DESCRIPTION
+
+The functions in this module handle sending text to a printer.
+
+=head1 FUNCTIONS
+
+=over 2
+
+=cut
+
+ at ISA = qw(Exporter);
+ at EXPORT = qw(&remoteprint &printreserve &printslip);
+
+=item remoteprint
+
+ &remoteprint($env, $items, $borrower);
+
+Prints the list of items in C<$items> to a printer.
+
+C<$env> is a reference-to-hash. C<$env-E<gt>{queue}> specifies the
+queue to print to; if it is empty or has the special value C<nulllp>,
+C<&remoteprint> will print to the file F</tmp/kohaiss>.
+
+C<$borrower> is a reference-to-hash giving information about a patron.
+This may be gotten from C<&getpatroninformation>. The patron's name
+will be printed in the output.
+
+C<$items> is a reference-to-list, where each element is a
+reference-to-hash describing a borrowed item. C<$items> may be gotten
+from C<¤tissues>.
+
+=cut
+#'
+# FIXME - It'd be nifty if this could generate pretty PostScript.
+sub remoteprint {
+ my ($env,$items,$borrower)=@_;
+
+ (return) unless (C4::Context->boolean_preference('printcirculationslips'));
+ my $queue = $env->{'queue'};
+ # FIXME - If 'queue' is undefined or empty, then presumably it should
+ # mean "use the default queue", whatever the default is. Presumably
+ # the default depends on the physical location of the machine.
+ # FIXME - Perhaps "print to file" should be a supported option. Just
+ # set the queue to "file" (or " file", if real queues aren't allowed
+ # to have spaces in them). Or perhaps if $queue eq "" and
+ # $env->{file} ne "", then that should mean "print to $env->{file}".
+ if ($queue eq "" || $queue eq 'nulllp') {
+ open (PRINTER,">/tmp/kohaiss");
+ } else {
+ # FIXME - This assumes that 'lpr' exists, and works as expected.
+ # This is a reasonable assumption, but only because every other
+ # printing package has a wrapper script called 'lpr'. It'd still
+ # be better to be able to customize this.
+ open(PRINTER, "| lpr -P $queue > /dev/null") or die "Couldn't write to queue:$queue!\n";
+ }
+# print $queue;
+ #open (FILE,">/tmp/$file");
+ my $i=0;
+ my $brdata = $env->{'brdata'}; # FIXME - Not used
+ # FIXME - This is HLT-specific. Put this stuff in a customizable
+ # site-specific file somewhere.
+ print PRINTER "Horowhenua Library Trust\r\n";
+# print PRINTER "$brdata->{'branchname'}\r\n";
+ print PRINTER "Phone: 368-1953\r\n";
+ print PRINTER "Fax: 367-9218\r\n";
+ print PRINTER "Email: renewals\@library.org.nz\r\n\r\n\r\n";
+ print PRINTER "$borrower->{'cardnumber'}\r\n";
+ print PRINTER "$borrower->{'title'} $borrower->{'initials'} $borrower->{'surname'}\r\n";
+ # FIXME - Use for ($i = 0; $items->[$i]; $i++)
+ # Or better yet, foreach $item (@{$items})
+ while ($items->[$i]){
+# print $i;
+ my $itemdata = $items->[$i];
+ # FIXME - This is just begging for a Perl format.
+ print PRINTER "$i $itemdata->{'title'}\r\n";
+ print PRINTER "$itemdata->{'barcode'}";
+ print PRINTER " "x15;
+ print PRINTER "$itemdata->{'date_due'}\r\n";
+ $i++;
+ }
+ print PRINTER "\r\n\r\n\r\n\r\n\r\n\r\n\r\n";
+ if ($env->{'printtype'} eq "docket"){
+ #print chr(27).chr(105);
+ }
+ close PRINTER;
+ #system("lpr /tmp/$file");
+}
+
+sub printreserve {
+ my($env, $branchname, $bordata, $itemdata)=@_;
+ my $file=time;
+ my $printer = $env->{'printer'};
+ (return) unless (C4::Context->boolean_preference('printreserveslips'));
+ if ($printer eq "" || $printer eq 'nulllp') {
+ open (PRINTER,">>/tmp/kohares");
+ } else {
+ open (PRINTER, "| lpr -P $printer >/dev/null") or die "Couldn't write to queue:$!\n";
+ }
+ my @da = localtime(time());
+ my $todaysdate = "$da[2]:$da[1] $da[3]/$da[4]/$da[5]";
+
+#(1900+$datearr[5]).sprintf ("%0.2d", ($datearr[4]+1)).sprintf ("%0.2d", $datearr[3]);
+ my $slip = <<"EOF";
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Date: $todaysdate;
+
+ITEM RESERVED:
+$itemdata->{'title'} ($itemdata->{'author'})
+barcode: $itemdata->{'barcode'}
+
+COLLECT AT: $branchname
+
+BORROWER:
+$bordata->{'surname'}, $bordata->{'firstname'}
+card number: $bordata->{'cardnumber'}
+Phone: $bordata->{'phone'}
+$bordata->{'streetaddress'}
+$bordata->{'suburb'}
+$bordata->{'town'}
+$bordata->{'emailaddress'}
+
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+EOF
+ print PRINTER $slip;
+ close PRINTER;
+ return $slip;
+}
+
+=item printslip
+
+ &printslip($env, $borrowernumber)
+
+ print a slip for the given $borrowernumber
+
+=cut
+#'
+sub printslip {
+ my ($env,$borrowernumber)=@_;
+ my ($borrower, $flags) = getpatroninformation($env,$borrowernumber,0);
+ $env->{'todaysissues'}=1;
+ my ($borrowerissues) = currentissues($env, $borrower);
+ $env->{'nottodaysissues'}=1;
+ $env->{'todaysissues'}=0;
+ my ($borroweriss2)=currentissues($env, $borrower);
+ $env->{'nottodaysissues'}=0;
+ my $i=0;
+ my @issues;
+ foreach (sort {$a <=> $b} keys %$borrowerissues) {
+ $issues[$i]=$borrowerissues->{$_};
+ my $dd=$issues[$i]->{'date_due'};
+ #convert to nz style dates
+ #this should be set with some kinda config variable
+ my @tempdate=split(/-/,$dd);
+ $issues[$i]->{'date_due'}="$tempdate[2]/$tempdate[1]/$tempdate[0]";
+ $i++;
+ }
+ foreach (sort {$a <=> $b} keys %$borroweriss2) {
+ $issues[$i]=$borroweriss2->{$_};
+ my $dd=$issues[$i]->{'date_due'};
+ #convert to nz style dates
+ #this should be set with some kinda config variable
+ my @tempdate=split(/-/,$dd);
+ $issues[$i]->{'date_due'}="$tempdate[2]/$tempdate[1]/$tempdate[0]";
+ $i++;
+ }
+ remoteprint($env,\@issues,$borrower);
+}
+
+END { } # module clean-up code here (global destructor)
+
+1;
+__END__
+
+=back
+
+=head1 AUTHOR
+
+Koha Developement team <info at koha.org>
+
+=head1 SEE ALSO
+
+C4::Circulation::Circ2(3)
+
+=cut
Index: Record.pm
===================================================================
RCS file: Record.pm
diff -N Record.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Record.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,575 @@
+package C4::Record;
+#
+# Copyright 2006 (C) LibLime
+# Joshua Ferraro <jmf at liblime.com>
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+#
+# $Id: Record.pm,v 1.1.2.1 2007/03/10 01:35:34 tgarip1957 Exp $
+#
+use strict; use warnings; #FIXME: turn off warnings before release
+
+# please specify in which methods a given module is used
+use MARC::Record; # marc2marcxml, marcxml2marc, html2marc, changeEncoding
+use MARC::File::XML; # marc2marcxml, marcxml2marc, html2marcxml, changeEncoding
+#use MARC::Crosswalk::DublinCore; # marc2dcxml
+#use MODS::Record; # marc2modsxml
+use Unicode::Normalize; # _entity_encode
+
+use vars qw($VERSION @ISA @EXPORT);
+
+# set the version for version checking
+$VERSION = do { my @v = '$Revision: 1.1.2.1 $' =~ /\d+/g;
+ shift(@v) . "." . join("_", map {sprintf "%03d", $_ } @v); };
+
+ at ISA = qw(Exporter);
+
+# only export API methods
+
+ at EXPORT = qw(
+ &marc2marc
+ &marc2marcxml
+ &marcxml2marc
+ &marc2dcxml
+ &marc2modsxml
+
+ &html2marcxml
+ &html2marc
+ &changeEncoding
+);
+
+=head1 NAME
+
+C4::Record - MARC, MARCXML, DC, MODS, XML, etc. Record Management Functions and API
+
+=head1 SYNOPSIS
+
+New in Koha 3.x. This module handles all record-related management functions.
+
+=head1 API (EXPORTED FUNCTIONS)
+
+=head2 marc2marc - Convert from one flavour of ISO-2709 to another
+
+=over 4
+
+my ($error,$newmarc) = marc2marc($marc,$to_flavour,$from_flavour,$encoding);
+
+Returns an ISO-2709 scalar
+
+=back
+
+=cut
+
+sub marc2marc {
+ my ($marc,$to_flavour,$from_flavour,$encoding) = @_;
+ my $error = "Feature not yet implemented\n";
+ return ($error,$marc);
+}
+
+=head2 marc2marcxml - Convert from ISO-2709 to MARCXML
+
+=over 4
+
+my ($error,$marcxml) = marc2marcxml($marc,$encoding,$flavour);
+
+Returns a MARCXML scalar
+
+=over 2
+
+C<$marc> - an ISO-2709 scalar or MARC::Record object
+
+C<$encoding> - UTF-8 or MARC-8 [UTF-8]
+
+C<$flavour> - MARC21 or UNIMARC
+
+C<$dont_entity_encode> - a flag that instructs marc2marcxml not to entity encode the xml before returning (optional)
+
+=back
+
+=back
+
+=cut
+
+sub marc2marcxml {
+ my ($marc,$encoding,$flavour,$dont_entity_encode) = @_;
+ my $error; # the error string
+ my $marcxml; # the final MARCXML scalar
+
+ # test if it's already a MARC::Record object, if not, make it one
+ my $marc_record_obj;
+ if ($marc =~ /^MARC::Record/) { # it's already a MARC::Record object
+ $marc_record_obj = $marc;
+ } else { # it's not a MARC::Record object, make it one
+ eval { $marc_record_obj = MARC::Record->new_from_usmarc($marc) }; # handle exceptions
+
+ # conversion to MARC::Record object failed, populate $error
+ if ($@) { $error .="\nCreation of MARC::Record object failed: ".$MARC::File::ERROR };
+ }
+ # only proceed if no errors so far
+ unless ($error) {
+
+ # check the record for warnings
+ my @warnings = $marc_record_obj->warnings();
+ if (@warnings) {
+ warn "\nWarnings encountered while processing ISO-2709 record with title \"".$marc_record_obj->title()."\":\n";
+ foreach my $warn (@warnings) { warn "\t".$warn };
+ }
+ unless($encoding) {$encoding = "UTF-8"}; # set default encoding
+ unless($flavour) {$flavour = C4::Context->preference("marcflavour")}; # set default MARC flavour
+
+ # attempt to convert the record to MARCXML
+ eval { $marcxml = $marc_record_obj->as_xml_record($flavour) }; #handle exceptions
+
+ # record creation failed, populate $error
+ if ($@) {
+ $error .= "Creation of MARCXML failed:".$MARC::File::ERROR;
+ $error .= "Additional information:\n";
+ my @warnings = $@->warnings();
+ foreach my $warn (@warnings) { $error.=$warn."\n" };
+
+ # record creation was successful
+ } else {
+
+ # check the record for warning flags again (warnings() will be cleared already if there was an error, see above block
+ @warnings = $marc_record_obj->warnings();
+ if (@warnings) {
+ warn "\nWarnings encountered while processing ISO-2709 record with title \"".$marc_record_obj->title()."\":\n";
+ foreach my $warn (@warnings) { warn "\t".$warn };
+ }
+ }
+
+ # only proceed if no errors so far
+ unless ($error) {
+
+ # entity encode the XML unless instructed not to
+ unless ($dont_entity_encode) {
+ my ($marcxml_entity_encoded) = _entity_encode($marcxml);
+ $marcxml = $marcxml_entity_encoded;
+ }
+ }
+ }
+ # return result to calling program
+ return ($error,$marcxml);
+}
+
+=head2 marcxml2marc - Convert from MARCXML to ISO-2709
+
+=over 4
+
+my ($error,$marc) = marcxml2marc($marcxml,$encoding,$flavour);
+
+Returns an ISO-2709 scalar
+
+=over 2
+
+C<$marcxml> - a MARCXML record
+
+C<$encoding> - UTF-8 or MARC-8 [UTF-8]
+
+C<$flavour> - MARC21 or UNIMARC
+
+=back
+
+=back
+
+=cut
+
+sub marcxml2marc {
+ my ($marcxml,$encoding,$flavour) = @_;
+ my $error; # the error string
+ my $marc; # the final ISO-2709 scalar
+ unless($encoding) {$encoding = "UTF-8"}; # set the default encoding
+ unless($flavour) {$flavour = C4::Context->preference("marcflavour")}; # set the default MARC flavour
+
+ # attempt to do the conversion
+ eval { $marc = MARC::Record->new_from_xml($marcxml,$encoding,$flavour) }; # handle exceptions
+
+ # record creation failed, populate $error
+ if ($@) {$error .="\nCreation of MARCXML Record failed: ".$@;
+ $error.=$MARC::File::ERROR if ($MARC::File::ERROR);
+ };
+ # return result to calling program
+ return ($error,$marc);
+}
+
+=head2 marc2dcxml - Convert from ISO-2709 to Dublin Core
+
+=over 4
+
+my ($error,$dcxml) = marc2dcxml($marc,$qualified);
+
+Returns a DublinCore::Record object, will eventually return a Dublin Core scalar
+
+FIXME: should return actual XML, not just an object
+
+=over 2
+
+C<$marc> - an ISO-2709 scalar or MARC::Record object
+
+C<$qualified> - specify whether qualified Dublin Core should be used in the input or output [0]
+
+=back
+
+=back
+
+=cut
+
+sub marc2dcxml {
+ my ($marc,$qualified) = @_;
+ my $error;
+ # test if it's already a MARC::Record object, if not, make it one
+ my $marc_record_obj;
+ if ($marc =~ /^MARC::Record/) { # it's already a MARC::Record object
+ $marc_record_obj = $marc;
+ } else { # it's not a MARC::Record object, make it one
+ eval { $marc_record_obj = MARC::Record->new_from_usmarc($marc) }; # handle exceptions
+
+ # conversion to MARC::Record object failed, populate $error
+ if ($@) {
+ $error .="\nCreation of MARC::Record object failed: ".$MARC::File::ERROR;
+ }
+ }
+ my $crosswalk = MARC::Crosswalk::DublinCore->new;
+ if ($qualified) {
+ $crosswalk = MARC::Crosswalk::DublinCore->new( qualified => 1 );
+ }
+ my $dcxml = $crosswalk->as_dublincore($marc_record_obj);
+ return ($error,$dcxml);
+}
+=head2 marc2modsxml - Convert from ISO-2709 to MODS
+
+=over 4
+
+my ($error,$modsxml) = marc2modsxml($marc);
+
+Returns a MODS scalar
+
+=back
+
+=cut
+
+sub marc2modsxml {
+ use XML::XSLT;
+ #use XML::LibXSLT;
+ my ($marc) = @_;
+ my $error;
+ my $marcxml;
+
+ # open some files for testing
+ open MARCBIG21MARC21SLIM,"/home/koha/head/koha/C4/MARC21slim2MODS3-1.xsl" or die $!;
+ my $marcbig2marc21_slim; # = scalar (MARC21MARC8);
+ foreach my $line (<MARCBIG21MARC21SLIM>) {
+ $marcbig2marc21_slim .= $line;
+ }
+
+ # set some defailts
+ my $to_encoding = "UTF-8";
+ my $flavour = "MARC21";
+
+ # first convert our ISO-2709 to MARCXML
+ ($error,$marcxml) = marc2marcxml($marc,$to_encoding,$flavour);
+ my $xslt_obj = XML::XSLT->new ($marcbig2marc21_slim, warnings => 1);
+ $xslt_obj->transform ($marcxml);
+ my $xslt_string = $xslt_obj->toString;
+ $xslt_obj->dispose();
+ warn $xslt_string;
+ return ($error,$xslt_string);
+}
+=head2 html2marcxml
+
+=over 4
+
+my ($error,$marcxml) = html2marcxml($tags,$subfields,$values,$indicator,$ind_tag);
+
+Returns a MARCXML scalar
+
+this is used in addbiblio.pl and additem.pl to build the MARCXML record from
+the form submission.
+
+FIXME: this could use some better code documentation
+
+=back
+
+=cut
+
+sub html2marcxml {
+ my ($tags,$subfields,$values,$indicator,$ind_tag) = @_;
+ my $error;
+ # add the header info
+ my $marcxml= MARC::File::XML::header(C4::Context->preference('TemplateEncoding'),C4::Context->preference('marcflavour'));
+
+ # some flags used to figure out where in the record we are
+ my $prevvalue;
+ my $prevtag=-1;
+ my $first=1;
+ my $j = -1;
+
+ # handle characters that would cause the parser to choke FIXME: is there a more elegant solution?
+ for (my $i=0;$i<=@$tags;$i++){
+ @$values[$i] =~ s/&/&/g;
+ @$values[$i] =~ s/</</g;
+ @$values[$i] =~ s/>/>/g;
+ @$values[$i] =~ s/"/"/g;
+ @$values[$i] =~ s/'/'/g;
+
+ if ((@$tags[$i] ne $prevtag)){
+ $j++ unless (@$tags[$i] eq "");
+ #warn "IND:".substr(@$indicator[$j],0,1).substr(@$indicator[$j],1,1)." ".@$tags[$i];
+ if (!$first){
+ $marcxml.="</datafield>\n";
+ if ((@$tags[$i] > 10) && (@$values[$i] ne "")){
+ my $ind1 = substr(@$indicator[$j],0,1);
+ my $ind2 = substr(@$indicator[$j],1,1);
+ $marcxml.="<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
+ $marcxml.="<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
+ $first=0;
+ } else {
+ $first=1;
+ }
+ } else {
+ if (@$values[$i] ne "") {
+ # handle the leader
+ if (@$tags[$i] eq "000") {
+ $marcxml.="<leader>@$values[$i]</leader>\n";
+ $first=1;
+ # rest of the fixed fields
+ } elsif (@$tags[$i] < 010) { #FIXME: <10 was the way it was, there might even be a better way
+ $marcxml.="<controlfield tag=\"@$tags[$i]\">@$values[$i]</controlfield>\n";
+ $first=1;
+ } else {
+ my $ind1 = substr(@$indicator[$j],0,1);
+ my $ind2 = substr(@$indicator[$j],1,1);
+ $marcxml.="<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
+ $marcxml.="<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
+ $first=0;
+ }
+ }
+ }
+ } else { # @$tags[$i] eq $prevtag
+ if (@$values[$i] eq "") {
+ } else {
+ if ($first){
+ my $ind1 = substr(@$indicator[$j],0,1);
+ my $ind2 = substr(@$indicator[$j],1,1);
+ $marcxml.="<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
+ $first=0;
+ }
+ $marcxml.="<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
+ }
+ }
+ $prevtag = @$tags[$i];
+ }
+ $marcxml.= MARC::File::XML::footer();
+ #warn $marcxml;
+ return ($error,$marcxml);
+}
+
+=head2 html2marc
+
+=over 4
+
+Probably best to avoid using this ... it has some rather striking problems:
+
+=over 2
+
+* saves blank subfields
+
+* subfield order is hardcoded to always start with 'a' for repeatable tags (because it is hardcoded in the addfield routine).
+
+* only possible to specify one set of indicators for each set of tags (ie, one for all the 650s). (because they were stored in a hash with the tag as the key).
+
+* the underlying routines didn't support subfield reordering or subfield repeatability.
+
+=back
+
+I've left it in here because it could be useful if someone took the time to fix it. -- kados
+
+=back
+
+=cut
+
+sub html2marc {
+ my ($dbh,$rtags,$rsubfields,$rvalues,%indicators) = @_;
+ my $prevtag = -1;
+ my $record = MARC::Record->new();
+# my %subfieldlist=();
+ my $prevvalue; # if tag <10
+ my $field; # if tag >=10
+ for (my $i=0; $i< @$rtags; $i++) {
+ # rebuild MARC::Record
+# warn "0=>".@$rtags[$i].@$rsubfields[$i]." = ".@$rvalues[$i].": ";
+ if (@$rtags[$i] ne $prevtag) {
+ if ($prevtag < 10) {
+ if ($prevvalue) {
+ if (($prevtag ne '000') && ($prevvalue ne "")) {
+ $record->add_fields((sprintf "%03s",$prevtag),$prevvalue);
+ } elsif ($prevvalue ne ""){
+ $record->leader($prevvalue);
+ }
+ }
+ } else {
+ if (($field) && ($field ne "")) {
+ $record->add_fields($field);
+ }
+ }
+ $indicators{@$rtags[$i]}.=' ';
+ # skip blank tags, I hope this works
+ if (@$rtags[$i] eq ''){
+ $prevtag = @$rtags[$i];
+ undef $field;
+ next;
+ }
+ if (@$rtags[$i] <10) {
+ $prevvalue= @$rvalues[$i];
+ undef $field;
+ } else {
+ undef $prevvalue;
+ if (@$rvalues[$i] eq "") {
+ undef $field;
+ } else {
+ $field = MARC::Field->new( (sprintf "%03s",@$rtags[$i]), substr($indicators{@$rtags[$i]},0,1),substr($indicators{@$rtags[$i]},1,1), @$rsubfields[$i] => @$rvalues[$i]);
+ }
+# warn "1=>".@$rtags[$i].@$rsubfields[$i]." = ".@$rvalues[$i].": ".$field->as_formatted;
+ }
+ $prevtag = @$rtags[$i];
+ } else {
+ if (@$rtags[$i] <10) {
+ $prevvalue=@$rvalues[$i];
+ } else {
+ if (length(@$rvalues[$i])>0) {
+ $field->add_subfields(@$rsubfields[$i] => @$rvalues[$i]);
+# warn "2=>".@$rtags[$i].@$rsubfields[$i]." = ".@$rvalues[$i].": ".$field->as_formatted;
+ }
+ }
+ $prevtag= @$rtags[$i];
+ }
+ }
+ #}
+ # the last has not been included inside the loop... do it now !
+ #use Data::Dumper;
+ #warn Dumper($field->{_subfields});
+ $record->add_fields($field) if (($field) && $field ne "");
+ #warn "HTML2MARC=".$record->as_formatted;
+ return $record;
+}
+
+=head2 changeEncoding - Change the encoding of a record
+
+=over 4
+
+my ($error, $newrecord) = changeEncoding($record,$format,$flavour,$to_encoding,$from_encoding);
+
+Changes the encoding of a record
+
+=over 2
+
+C<$record> - the record itself can be in ISO-2709, a MARC::Record object, or MARCXML for now (required)
+
+C<$format> - MARC or MARCXML (required)
+
+C<$flavour> - MARC21 or UNIMARC, if MARC21, it will change the leader (optional) [defaults to Koha system preference]
+
+C<$to_encoding> - the encoding you want the record to end up in (optional) [UTF-8]
+
+C<$from_encoding> - the encoding the record is currently in (optional, it will probably be able to tell unless there's a problem with the record)
+
+=back
+
+FIXME: the from_encoding doesn't work yet
+
+FIXME: better handling for UNIMARC, it should allow management of 100 field
+
+FIXME: shouldn't have to convert to and from xml/marc just to change encoding someone needs to re-write MARC::Record's 'encoding' method to actually alter the encoding rather than just changing the leader
+
+=back
+
+=cut
+
+sub changeEncoding {
+ my ($record,$format,$flavour,$to_encoding,$from_encoding) = @_;
+ my $newrecord;
+ my $error;
+ unless($flavour) {$flavour = C4::Context->preference("marcflavour")};
+ unless($to_encoding) {$to_encoding = "UTF-8"};
+
+ # ISO-2709 Record (MARC21 or UNIMARC)
+ if (lc($format) =~ /^marc$/o) {
+ # if we're converting encoding of an ISO2709 file, we need to roundtrip through XML
+ # because MARC::Record doesn't directly provide us with an encoding method
+ # It's definitely less than idea and should be fixed eventually - kados
+ my $marcxml; # temporary storage of MARCXML scalar
+ ($error,$marcxml) = marc2marcxml($record,$to_encoding,$flavour);
+ unless ($error) {
+ ($error,$newrecord) = marcxml2marc($marcxml,$to_encoding,$flavour);
+ }
+
+ # MARCXML Record
+ } elsif (lc($format) =~ /^marcxml$/o) { # MARCXML Record
+ my $marc;
+ ($error,$marc) = marcxml2marc($record,$to_encoding,$flavour);
+ unless ($error) {
+ ($error,$newrecord) = marc2marcxml($record,$to_encoding,$flavour);
+ }
+ } else {
+ $error.="Unsupported record format:".$format;
+ }
+ return ($error,$newrecord);
+}
+
+=head1 INTERNAL FUNCTIONS
+
+=head2 _entity_encode - Entity-encode an array of strings
+
+=over 4
+
+my ($entity_encoded_string) = _entity_encode($string);
+
+or
+
+my (@entity_encoded_strings) = _entity_encode(@strings);
+
+Entity-encode an array of strings
+
+=back
+
+=cut
+
+sub _entity_encode {
+ my @strings = @_;
+ my @strings_entity_encoded;
+ foreach my $string (@strings) {
+ my $nfc_string = NFC($string);
+ $nfc_string =~ s/([\x{0080}-\x{fffd}])/sprintf('&#x%X;',ord($1))/sgoe;
+ push @strings_entity_encoded, $nfc_string;
+ }
+ return @strings_entity_encoded;
+}
+
+END { } # module clean-up code here (global destructor)
+1;
+__END__
+
+=back
+
+=head1 AUTHOR
+
+Joshua Ferraro <jmf at liblime.com>
+
+=head1 MODIFICATIONS
+
+# $Id: Record.pm,v 1.1.2.1 2007/03/10 01:35:34 tgarip1957 Exp $
+
+=cut
Index: Reserves2.pm
===================================================================
RCS file: Reserves2.pm
diff -N Reserves2.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Reserves2.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,759 @@
+# -*- tab-width: 8 -*-
+# NOTE: This file uses standard 8-character tabs
+
+package C4::Reserves2;
+
+# $Id: Reserves2.pm,v 1.1.2.1 2007/03/10 01:35:34 tgarip1957 Exp $
+
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is hard coded with koha-reserves table to be used only by the OPAC -TG.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+require Exporter;
+
+use C4::Context;
+use C4::Biblio;
+
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
+
+# set the version for version checking
+$VERSION = 0.01;
+
+=head1 NAME
+
+C4::Reserves2 - FIXME
+
+=head1 SYNOPSIS
+
+ use C4::Reserves2;
+
+=head1 DESCRIPTION
+
+FIXME
+
+=head1 FUNCTIONS
+
+=over 2
+
+=cut
+
+ at ISA = qw(Exporter);
+# FIXME Take out CalcReserveFee after it can be removed from opac-reserves.pl
+ at EXPORT = qw(&FindReserves
+ &FindAllReserves
+ &CheckReserves
+ &CheckWaiting
+ &CancelReserve
+ &CalcReserveFee
+ &FillReserve
+ &ReserveWaiting
+ &CreateReserve
+ &UpdateReserves
+ &UpdateReserve
+ &getreservetitle
+ &Findgroupreserve
+ &findActiveReserve
+
+ );
+
+# make all your functions, whether exported or not;
+
+=item FindReserves
+
+ ($count, $results) = &FindReserves($biblionumber, $borrowernumber);
+
+Looks books up in the reserves. C<$biblionumber> is the biblionumber
+of the book to look up. C<$borrowernumber> is the borrower number of a
+patron whose books to look up.
+
+Either C<$biblionumber> or C<$borrowernumber> may be the empty string,
+but not both. If both are specified, C<&FindReserves> looks up the
+given book for the given patron. If only C<$biblionumber> is
+specified, C<&FindReserves> looks up that book for all patrons. If
+only C<$borrowernumber> is specified, C<&FindReserves> looks up all of
+that patron's reserves. If neither is specified, C<&FindReserves>
+barfs.
+
+C<&FindReserves> returns a two-element array:
+
+C<$count> is the number of elements in C<$results>.
+
+C<$results> is a reference-to-array; each element is a
+reference-to-hash, whose keys are (I think) all of the fields of the
+reserves, borrowers, and biblio tables of the Koha database.
+
+=cut
+#'
+sub FindReserves {
+ my ($bib, $bor) = @_;
+ my @params;
+
+ my $dbh = C4::Context->dbh;
+ # Find the desired items in the reserves
+ my $query="SELECT *, reserves.branchcode, reserves.timestamp as rtimestamp, DATE_FORMAT(reserves.timestamp, '%T') AS time
+ FROM reserves,borrowers,items ";
+ if ($bib ne ''){
+ #$bib = $dbh->quote($bib);
+ if ($bor ne ''){
+ # Both $bib and $bor specified
+ # Find a particular book for a particular patron
+ #$bor = $dbh->quote($bor);
+ $query .= "WHERE (reserves.biblionumber = ?) and
+ (borrowers.borrowernumber = ?) and
+ (reserves.borrowernumber = borrowers.borrowernumber) and
+ (reserves.itemnumber=items.itemnumber) and
+ (cancellationdate IS NULL) and
+ (found <> 1) ";
+
+ push @params, $bib, $bor;
+ } else {
+ # $bib specified, but not $bor
+ # Find a particular book for all patrons
+ $query .= "WHERE (reserves.borrowernumber = borrowers.borrowernumber) and
+ (reserves.biblionumber = ?) and
+ (reserves.itemnumber=items.itemnumber) and
+ (cancellationdate IS NULL) and
+ (found <> 1) ";
+
+ push @params, $bib;
+ }
+ } else {
+ $query .= "WHERE (reserves.biblionumber = items.biblionumber) and
+ (borrowers.borrowernumber = ?) and
+ (reserves.borrowernumber = borrowers.borrowernumber) and
+ (reserves.itemnumber=items.itemnumber) and
+ (cancellationdate IS NULL) and
+ (found <> 1)";
+
+ push @params, $bor;
+ }
+ $query.=" order by reserves.timestamp";
+ my $sth = $dbh->prepare($query);
+ $sth->execute(@params);
+
+ my $i = 0;
+ my @results;
+ while (my $data = $sth->fetchrow_hashref){
+ my ($bibdata) =XMLgetbibliohash($dbh,$data->{'biblionumber'});
+ my ($itemhash)=XMLgetitemhash($dbh,$data->{'itemnumber'});
+ $data->{'holdingbranch'}=XML_readline_onerecord($itemhash,"holdingbranch","holdings");
+ $data->{'author'} =XML_readline_onerecord($bibdata,"author","biblios");
+ $data->{'publishercode'} = XML_readline_onerecord($bibdata,"publishercode","biblios");
+ $data->{'publicationyear'} = XML_readline_onerecord($bibdata,"publicationyear","biblios");
+ $data->{'title'} = XML_readline_onerecord($bibdata,"title","biblios");
+ push @results, $data;
+ $i++;
+ }
+ $sth->finish;
+
+ return($i,\@results);
+}
+
+=item FindAllReserves
+
+ ($count, $results) = &FindAllReserves($biblionumber, $borrowernumber);
+
+Looks books up in the reserves. C<$biblionumber> is the biblionumber
+of the book to look up. C<$borrowernumber> is the borrower number of a
+patron whose books to look up.
+
+Either C<$biblionumber> or C<$borrowernumber> may be the empty string,
+but not both. If both are specified, C<&FindReserves> looks up the
+given book for the given patron. If only C<$biblionumber> is
+specified, C<&FindReserves> looks up that book for all patrons. If
+only C<$borrowernumber> is specified, C<&FindReserves> looks up all of
+that patron's reserves. If neither is specified, C<&FindReserves>
+barfs.
+
+C<&FindAllReserves> returns a two-element array:
+
+C<$count> is the number of elements in C<$results>.
+
+C<$results> is a reference-to-array; each element is a
+reference-to-hash, whose keys are (I think) all of the fields of the
+reserves, borrowers, and biblio tables of the Koha database.
+
+=cut
+#'
+sub FindAllReserves {
+ my ($bib, $bor) = @_;
+ my @params;
+
+my $dbh;
+
+ $dbh = C4::Context->dbh;
+
+ # Find the desired items in the reserves
+ my $query="SELECT *,
+ reserves.branchcode,
+ biblio.title AS btitle,
+ reserves.timestamp as rtimestamp,
+ DATE_FORMAT(reserves.timestamp, '%T') AS time
+ FROM reserves,
+ borrowers,
+ biblio ";
+ if ($bib ne ''){
+ #$bib = $dbh->quote($bib);
+ if ($bor ne ''){
+ # Both $bib and $bor specified
+ # Find a particular book for a particular patron
+ #$bor = $dbh->quote($bor);
+ $query .= "WHERE (reserves.biblionumber = ?) and
+ (borrowers.borrowernumber = ?) and
+ (reserves.borrowernumber = borrowers.borrowernumber) and
+ (biblio.biblionumber = ?) and
+ (cancellationdate IS NULL) and
+ (found <> 1) and
+ (reservefrom > NOW())";
+ push @params, $bib, $bor, $bib;
+ } else {
+ # $bib specified, but not $bor
+ # Find a particular book for all patrons
+ $query .= "WHERE (reserves.borrowernumber = borrowers.borrowernumber) and
+ (biblio.biblionumber = ?) and
+ (reserves.biblionumber = ?) and
+ (cancellationdate IS NULL) and
+ (found <> 1) and
+ (reservefrom > NOW())";
+ push @params, $bib, $bib;
+ }
+ } else {
+ $query .= "WHERE (reserves.biblionumber = biblio.biblionumber) and
+ (borrowers.borrowernumber = ?) and
+ (reserves.borrowernumber = borrowers.borrowernumber) and
+ (reserves.biblionumber = biblio.biblionumber) and
+ (cancellationdate IS NULL) and
+ (found <> 1) and
+ (reservefrom > NOW())";
+ push @params, $bor;
+ }
+ $query.=" order by reserves.timestamp";
+ my $sth = $dbh->prepare($query);
+ $sth->execute(@params);
+
+ my $i = 0;
+ my @results;
+ while (my $data = $sth->fetchrow_hashref){
+ my $bibdata = C4::Search::bibdata($data->{'biblionumber'});
+ $data->{'author'} = $bibdata->{'author'};
+ $data->{'publishercode'} = $bibdata->{'publishercode'};
+ $data->{'publicationyear'} = $bibdata->{'publicationyear'};
+ $data->{'title'} = $bibdata->{'title'};
+ push @results, $data;
+ $i++;
+ }
+ $sth->finish;
+
+ return($i,\@results);
+}
+
+=item CheckReserves
+
+ ($status, $reserve) = &CheckReserves($itemnumber, $barcode);
+
+Find a book in the reserves.
+
+C<$itemnumber> is the book's item number. C<$barcode> is its barcode.
+Either one, but not both, may be false. If both are specified,
+C<&CheckReserves> uses C<$itemnumber>.
+
+$itemnubmer can be false, in which case uses the barcode. (Never uses
+both. $itemnumber gets priority).
+
+As I understand it, C<&CheckReserves> looks for the given item in the
+reserves. If it is found, that's a match, and C<$status> is set to
+C<Waiting>.
+
+Otherwise, it finds the most important item in the reserves with the
+same biblio number as this book (I'm not clear on this) and returns it
+with C<$status> set to C<Reserved>.
+
+C<&CheckReserves> returns a two-element list:
+
+C<$status> is either C<Waiting>, C<Reserved> (see above), or 0.
+
+C<$reserve> is the reserve item that matched. It is a
+reference-to-hash whose keys are mostly the fields of the reserves
+table in the Koha database.
+
+=cut
+#'
+sub CheckReserves {
+ my ($item, $barcode) = @_;
+# warn "In CheckReserves: itemnumber = $item";
+ my $dbh = C4::Context->dbh;
+ my $sth;
+ if ($item) {
+
+ } else {
+ my $qbc=$dbh->quote($barcode);
+ # Look up the item by barcode
+ $sth=$dbh->prepare("SELECT items.itemnumber
+ FROM items
+ WHERE barcode=$qbc");
+ $sth->execute;
+ ($item) = $sth->fetchrow;
+ $sth->finish;
+ }
+
+
+# if item is not for loan it cannot be reserved either.....
+# return (0, 0) if ($notforloan);
+# get the reserves...
+ # Find this item in the reserves
+ my ($count, @reserves) = Findgroupreserve($item);
+ # $priority and $highest are used to find the most important item
+ # in the list returned by &Findgroupreserve. (The lower $priority,
+ # the more important the item.)
+ # $highest is the most important item we've seen so far.
+ my $priority = 10000000;
+ my $highest;
+ if ($count) {
+ foreach my $res (@reserves) {
+ if ($res->{found} eq "W"){
+ return ("Waiting", $res);
+ }else{
+ # See if this item is more important than what we've got
+ # so far.
+ if ($res->{'priority'} != 0 && $res->{'priority'} < $priority) {
+ $priority = $res->{'priority'};
+ $highest = $res;
+ }
+ }
+ }
+ }
+
+ # If we get this far, then no exact match was found. Print the
+ # most important item on the list. I think this tells us who's
+ # next in line to get this book.
+ if ($highest) { # FIXME - $highest might be undefined
+ $highest->{'itemnumber'} = $item;
+ return ("Reserved", $highest);
+ } else {
+ return (0, 0);
+ }
+}
+
+=item CancelReserve
+
+ &CancelReserve($reserveid);
+
+Cancels a reserve.
+
+Use reserveid to cancel the reservation.
+
+C<$reserveid> is the reserve ID to cancel.
+
+=cut
+#'
+sub CancelReserve {
+ my ($biblio, $item, $borr) = @_;
+
+my $dbh;
+
+ $dbh = C4::Context->dbh;
+
+ #warn "In CancelReserve";
+ if (($item and $borr) and (not $biblio)) {
+ # removing a waiting reserve record....
+ # update the database...
+ my $sth = $dbh->prepare("update reserves set cancellationdate = now(),
+ found = Null,
+ priority = 0
+ where itemnumber = ?
+ and borrowernumber = ?");
+ $sth->execute($item,$borr);
+ $sth->finish;
+ }
+ if (($biblio and $borr) and (not $item)) {
+ # removing a reserve record....
+ # get the prioritiy on this record....
+ my $priority;
+ my $sth=$dbh->prepare("SELECT priority FROM reserves
+ WHERE biblionumber = ?
+ AND borrowernumber = ?
+ AND cancellationdate is NULL
+ AND (found <> 1 )");
+ $sth->execute($biblio,$borr);
+ ($priority) = $sth->fetchrow_array;
+ $sth->finish;
+
+ # update the database, removing the record...
+ $sth = $dbh->prepare("update reserves set cancellationdate = now(),
+ found = 0,
+ priority = 0
+ where biblionumber = ?
+ and borrowernumber = ?
+ and cancellationdate is NULL
+ and (found <> 1 )");
+ $sth->execute($biblio,$borr);
+ $sth->finish;
+ # now fix the priority on the others....
+ fixpriority($priority, $biblio);
+ }
+}
+=item FillReserve
+
+ &FillReserve($reserveid, $itemnumber);
+
+Fill a reserve. If I understand this correctly, this means that the
+reserved book has been found and given to the patron who reserved it.
+
+C<$reserve> specifies the reserve id to fill.
+
+C<$itemnumber> specifies the borrowed itemnumber for the reserve.
+
+=cut
+#'
+sub FillReserve {
+ my ($res) = @_;
+my $dbh;
+ $dbh = C4::Context->dbh;
+ # fill in a reserve record....
+ # FIXME - Remove some of the redundancy here
+ my $biblio = $res->{'biblionumber'}; my $qbiblio =$biblio;
+ my $borr = $res->{'borrowernumber'};
+ my $resdate = $res->{'reservedate'};
+
+ # get the priority on this record....
+ my $priority;
+ {
+ my $query = "SELECT priority FROM reserves
+ WHERE biblionumber = ?
+ AND borrowernumber = ?
+ AND reservedate = ?";
+ my $sth=$dbh->prepare($query);
+ $sth->execute($qbiblio,$borr,$resdate);
+ ($priority) = $sth->fetchrow_array;
+ $sth->finish;
+ }
+
+ # update the database...
+ {
+ my $query = "UPDATE reserves SET found = 1,
+ priority = 0
+ WHERE biblionumber = ?
+ AND reservedate = ?
+ AND borrowernumber = ?";
+ my $sth = $dbh->prepare($query);
+ $sth->execute($qbiblio,$resdate,$borr);
+ $sth->finish;
+ }
+
+ # now fix the priority on the others (if the priority wasn't
+ # already sorted!)....
+ unless ($priority == 0) {
+ fixpriority($priority, $biblio);
+ }
+}
+
+# Only used internally
+# Decrements (makes more important) the reserves for all of the
+# entries waiting on the given book, if their priority is > $priority.
+sub fixpriority {
+ my ($priority, $biblio) = @_;
+my $dbh;
+ $dbh = C4::Context->dbh;
+
+ my ($count, $reserves) = FindReserves($biblio);
+ foreach my $rec (@$reserves) {
+ if ($rec->{'priority'} > $priority) {
+ my $sth = $dbh->prepare("UPDATE reserves SET priority = ?
+ WHERE biblionumber = ?
+ AND borrowernumber = ?
+ AND reservedate = ?");
+ $sth->execute($rec->{'priority'},$rec->{'biblionumber'},$rec->{'borrowernumber'},$rec->{'reservedate'});
+ $sth->finish;
+ }
+ }
+}
+
+# XXX - POD
+sub ReserveWaiting {
+ my ($item, $borr) = @_;
+
+my $dbh;
+
+ $dbh = C4::Context->dbh;
+
+# get priority and biblionumber....
+ my $sth = $dbh->prepare("SELECT reserves.priority as priority,
+ reserves.biblionumber as biblionumber,
+ reserves.branchcode as branchcode,
+ reserves.timestamp as timestamp
+ FROM reserves
+ WHERE reserves.itemnumber = ?
+ AND reserves.borrowernumber = ?
+ AND reserves.cancellationdate is NULL
+ AND (reserves.found <> '1' or reserves.found is NULL)");
+ $sth->execute($item,$borr);
+ my $data = $sth->fetchrow_hashref;
+ $sth->finish;
+ my $biblio = $data->{'biblionumber'};
+ my $timestamp = $data->{'timestamp'};
+# update reserves record....
+ $sth = $dbh->prepare("UPDATE reserves SET priority = 0, found = 'W'
+ WHERE borrowernumber = ?
+ AND itemnumber = ?
+ AND timestamp = ?");
+ $sth->execute($borr,$item,$timestamp);
+ $sth->finish;
+# now fix up the remaining priorities....
+ fixpriority($data->{'priority'}, $biblio);
+ my $branchcode = $data->{'branchcode'};
+ return $branchcode;
+}
+
+# XXX - POD
+sub CheckWaiting {
+ my ($borr)=@_;
+
+my $dbh;
+ $dbh = C4::Context->dbh;
+ my @itemswaiting;
+ my $sth = $dbh->prepare("SELECT * FROM reserves
+ WHERE borrowernumber = ?
+ AND reserves.found = 'W'
+ AND cancellationdate is NULL");
+ $sth->execute($borr);
+ while (my $data=$sth->fetchrow_hashref) {
+ push(@itemswaiting,$data);
+ }
+ $sth->finish;
+ return (scalar(@itemswaiting),\@itemswaiting);
+}
+
+=item Findgroupreserve
+
+ ($count, @results) = &Findgroupreserve($biblioitemnumber, $biblionumber);
+
+I don't know what this does, because I don't understand how reserve
+constraints work. I think the idea is that you reserve a particular
+biblio, and the constraint allows you to restrict it to a given
+biblioitem (e.g., if you want to borrow the audio book edition of "The
+Prophet", rather than the first available publication).
+
+C<&Findgroupreserve> returns a two-element array:
+
+C<$count> is the number of elements in C<@results>.
+
+C<@results> is an array of references-to-hash whose keys are mostly
+fields from the reserves table of the Koha database, plus
+C<biblioitemnumber>.
+
+=cut
+#'
+sub Findgroupreserve {
+ my ($itemnumber)=@_;
+
+my $dbh = C4::Context->dbh;
+
+ my $sth = $dbh->prepare("SELECT *
+ FROM reserves
+ WHERE (itemnumber = ?) AND
+ (cancellationdate IS NULL) AND
+ (found <> 1)
+ ORDER BY timestamp");
+ $sth->execute($itemnumber);
+ my @results;
+ while (my $data = $sth->fetchrow_hashref) {
+ push(@results,$data);
+ }
+ $sth->finish;
+ return(scalar(@results), at results);
+}
+
+# FIXME - A somewhat different version of this function appears in
+# C4::Reserves. Pick one and stick with it.
+# XXX - POD
+sub CreateReserve {
+ my ($env, $borrnum,$registeredby ,$biblionumber,$reservefrom, $reserveto, $branch,
+ $constraint, $priority, $notes, $title,$bibitems,$itemnumber) = @_;
+
+my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("INSERT INTO reserves
+ (borrowernumber, registeredby, reservedate, biblionumber, reservefrom,
+ reserveto, branchcode, constrainttype, priority, found, reservenotes,itemnumber)
+ VALUES (?, ?, NOW(),?,?,?,?,?,?,0,?,?)");
+ $sth->execute($borrnum, $registeredby, $biblionumber, $reservefrom, $reserveto, $branch, $constraint, $priority, $notes,$itemnumber);
+my $fee=CalcReserveFee($env,$borrnum,$biblionumber,$constraint,$bibitems);
+ if ($fee > 0) {
+
+ my $nextacctno = &getnextacctno($env,$borrnum,$dbh);
+ my $usth = $dbh->prepare("insert into accountlines
+ (borrowernumber,accountno,date,amount,description,accounttype,amountoutstanding)
+ values
+ (?,?,now(),?,?,'Res',?)");
+ $usth->execute($borrnum,$nextacctno,$fee,'Reserve Charge -'. $title,$fee);
+ $usth->finish;
+ }
+ return 1;
+}
+
+# FIXME - A functionally identical version of this function appears in
+# C4::Reserves. Pick one and stick with it.
+# XXX - Internal use only
+# FIXME - opac-reserves.pl need to use it, temporarily put into @EXPORT
+
+sub CalcReserveFee {
+ my ($env,$borrnum,$biblionumber,$constraint,$bibitems) = @_;
+ #check for issues;
+my $dbh = C4::Context->dbh;
+
+
+ my $const = lc substr($constraint,0,1);
+ my $sth = $dbh->prepare("SELECT * FROM borrowers,categories
+ WHERE (borrowernumber = ?)
+ AND (borrowers.categorycode = categories.categorycode)");
+ $sth->execute($borrnum);
+ my $data = $sth->fetchrow_hashref;
+ $sth->finish();
+ my $fee = $data->{'reservefee'};
+
+ if ($fee > 0) {
+ # check for items on issue
+
+
+ my $issues = 0;
+ my $x = 0;
+ my $allissued = 1;
+
+ my $sth2 = $dbh->prepare("SELECT * FROM items
+ WHERE biblionumber = ?");
+ $sth2->execute($biblionumber);
+ while (my $itdata=$sth2->fetchrow_hashref) {
+ my $sth3 = $dbh->prepare("SELECT * FROM issues
+ WHERE itemnumber = ?
+ AND returndate IS NULL");
+ $sth3->execute($itdata->{'itemnumber'});
+ if (my $isdata=$sth3->fetchrow_hashref) {
+ } else {
+ $allissued = 0;
+ }
+ }
+
+
+ if ($allissued == 0) {
+ my $rsth = $dbh->prepare("SELECT * FROM reserves WHERE biblionumber = ?");
+ $rsth->execute($biblionumber);
+ if (my $rdata = $rsth->fetchrow_hashref) {
+ } else {
+ $fee = 0;
+ }
+ }
+ }
+# print "fee $fee";
+
+ return $fee;
+}
+
+# XXX - Internal use
+sub getnextacctno {
+ my ($env,$bornumber,$dbh)=@_;
+ my $nextaccntno = 1;
+ my $sth = $dbh->prepare("select * from accountlines
+ where (borrowernumber = ?)
+ order by accountno desc");
+ $sth->execute($bornumber);
+ if (my $accdata=$sth->fetchrow_hashref){
+ $nextaccntno = $accdata->{'accountno'} + 1;
+ }
+ $sth->finish;
+ return($nextaccntno);
+}
+
+# XXX - POD
+sub UpdateReserves {
+ #subroutine to update a reserve
+ my ($rank,$biblio,$borrower,$branch,$cataloger)=@_;
+ return if $rank eq "W";
+ return if $rank eq "n";
+my $dbh;
+ $dbh = C4::Context->dbh;
+
+ if ($rank eq "del") {
+ my $sth=$dbh->prepare("UPDATE reserves SET cancellationdate=now(),registeredby=?
+ WHERE biblionumber = ?
+ AND borrowernumber = ?
+ AND cancellationdate is NULL
+ AND (found <> 1 )");
+ $sth->execute($cataloger,$biblio, $borrower);
+ $sth->finish;
+ } else {
+ my $sth=$dbh->prepare("UPDATE reserves SET priority = ? ,branchcode = ?, found = 0
+ WHERE biblionumber = ?
+ AND borrowernumber = ?
+ AND cancellationdate is NULL
+ AND (found <> 1)");
+ $sth->execute($rank, $branch, $biblio, $borrower);
+ $sth->finish;
+ }
+}
+
+# XXX - POD
+sub UpdateReserve {
+ #subroutine to update a reserve
+ my ($reserveid, $timestamp) = @_;
+
+my $dbh;
+ $dbh = C4::Context->dbh;
+
+
+ my $sth=$dbh->prepare("UPDATE reserves
+ SET timestamp = $timestamp,
+ reservedate = DATE_FORMAT($timestamp, '%Y-%m-%d')
+ WHERE (reserveid = $reserveid)");
+ $sth->execute();
+ $sth->finish;
+}
+
+# XXX - PODXX Is this function Used?
+sub getreservetitle {
+ my ($biblio,$bor,$date,$timestamp)=@_;
+my $dbh = C4::Context->dbh;
+
+
+ my $sth=$dbh->prepare("Select * from reserveconstraints where
+ reserveconstraints.biblionumber=? and reserveconstraints.borrowernumber
+ = ? and reserveconstraints.reservedate=? and
+ reserveconstraints.timestamp=?");
+ $sth->execute($biblio,$bor,$date,$timestamp);
+ my $data=$sth->fetchrow_hashref;
+ $sth->finish;
+ return($data);
+}
+
+sub findActiveReserve {
+ my ($borrowernumber, $biblionumber, $from, $days) = @_;
+my $dbh = C4::Context->dbh;
+
+ my $sth = $dbh->prepare("SELECT *
+ FROM reserves
+ WHERE
+ borrowernumber = ?
+ AND biblionumber = ?
+ AND (cancellationdate IS NULL)
+ AND (found <> 1)
+ AND ((? BETWEEN reservefrom AND reserveto)
+ OR (ADDDATE(?, INTERVAL ? DAY) BETWEEN reservefrom AND reserveto))
+ ");
+ $sth->execute($borrowernumber, $biblionumber, $from, $from, $days);
+ return ($sth->rows);
+}
+
+1;
+__END__
\ No newline at end of file
Index: Review.pm
===================================================================
RCS file: Review.pm
diff -N Review.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Review.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,196 @@
+package C4::Review;
+
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+require Exporter;
+use C4::Context;
+
+use vars qw($VERSION @ISA @EXPORT);
+
+$VERSION = 0.01;
+
+=head1 NAME
+
+C4::Review - Perl Module containing routines for dealing with reviews of items
+
+=head1 SYNOPSIS
+
+ use C4::Review;
+
+
+ my $review=getreview($biblionumber,$borrowernumber);
+ savereview($biblionumber,$borrowernumber,$review);
+ updatereview($biblionumber,$borrowernumber,$review);
+ my $count=numberofreviews($biblionumber);
+ my $reviews=getreviews($biblionumber);
+ my $reviews=getallreviews($status);
+
+=head1 DESCRIPTION
+
+Review.pm provides many routines for manipulating reviews.
+
+=head1 FUNCTIONS
+
+=over 2
+
+=cut
+
+ at ISA = qw(Exporter);
+ at EXPORT = qw(getreview savereview updatereview numberofreviews
+ getreviews getallreviews approvereview deletereview);
+
+use vars qw();
+
+my $DEBUG = 0;
+
+=head2 getreview
+
+ $review = getreview($biblionumber,$borrowernumber);
+
+Takes a borrowernumber and a biblionumber and returns the review of that biblio
+
+
+=cut
+
+sub getreview {
+ my ( $biblionumber, $borrowernumber ) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query =
+ "SELECT * FROM reviews WHERE biblionumber=? and borrowernumber=?";
+ my $sth = $dbh->prepare($query);
+ $sth->execute( $biblionumber, $borrowernumber );
+ my $review = $sth->fetchrow_hashref();
+ $sth->finish();
+ return $review;
+}
+
+sub savereview {
+ my ( $biblionumber, $borrowernumber, $review ) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = "INSERT INTO reviews (borrowernumber,biblionumber,
+ review,approved,datereviewed) VALUES
+ (?,?,?,?,now())";
+ my $sth = $dbh->prepare($query);
+ $sth->execute( $borrowernumber, $biblionumber, $review, 0 );
+ $sth->finish();
+}
+
+sub updatereview {
+ my ( $biblionumber, $borrowernumber, $review ) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = "UPDATE reviews SET review=?,datereviewed=now(),approved=?
+ WHERE borrowernumber=? and biblionumber=?";
+ my $sth = $dbh->prepare($query);
+ $sth->execute( $review, 0, $borrowernumber, $biblionumber );
+ $sth->finish();
+
+}
+
+sub numberofreviews {
+ my ($biblionumber) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query =
+ "SELECT count(*) FROM reviews WHERE biblionumber=? and approved=?";
+ my $sth = $dbh->prepare($query);
+ $sth->execute( $biblionumber, 1 );
+ my $count = $sth->fetchrow_hashref;
+
+ $sth->finish();
+ return ( $count->{'count(*)'} );
+}
+
+sub getreviews {
+ my ( $biblionumber, $approved ) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query =
+"SELECT * FROM reviews WHERE biblionumber=? and approved=? order by datereviewed desc";
+ my $sth = $dbh->prepare($query) || warn $dbh->err_str;
+ $sth->execute( $biblionumber, $approved );
+ my @results;
+ while ( my $data = $sth->fetchrow_hashref() ) {
+ push @results, $data;
+ }
+ $sth->finish();
+ return ( \@results );
+}
+
+sub getallreviews {
+ my ($status) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query =
+ "SELECT * FROM reviews WHERE approved=? order by datereviewed desc";
+ my $sth = $dbh->prepare($query);
+ $sth->execute($status);
+ my @results;
+ while ( my $data = $sth->fetchrow_hashref() ) {
+ push @results, $data;
+ }
+ $sth->finish();
+ return ( \@results );
+}
+
+=head2 approvereview
+
+ approvereview($reviewid);
+
+Takes a reviewid and marks that review approved
+
+
+=cut
+
+sub approvereview {
+ my ($reviewid) = @_;
+ my $dbh = C4::Context->dbh();
+ my $query = "UPDATE reviews
+ SET approved=?
+ WHERE reviewid=?";
+ my $sth = $dbh->prepare($query);
+ $sth->execute( 1, $reviewid );
+ $sth->finish();
+}
+
+=head2 deletereview
+
+ deletereview($reviewid);
+
+Takes a reviewid and deletes it
+
+
+=cut
+
+sub deletereview {
+ my ($reviewid) = @_;
+ my $dbh = C4::Context->dbh();
+ my $query = "DELETE FROM reviews
+ WHERE reviewid=?";
+ my $sth = $dbh->prepare($query);
+ $sth->execute($reviewid);
+ $sth->finish();
+}
+
+1;
+__END__
+
+=back
+
+=head1 AUTHOR
+
+Koha Team
+
+=cut
Index: SMS.pm
===================================================================
RCS file: SMS.pm
diff -N SMS.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ SMS.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,149 @@
+package C4::SMS;
+#Written by tgarip at neu.edu.tr for SMS message sending and other SMS related services
+
+use strict;
+require Exporter;
+use LWP::UserAgent;
+use C4::Context;
+use vars qw($VERSION @ISA @EXPORT);
+$VERSION = 0.01;
+my $user=C4::Context->config('smsuser');
+my $pwd=C4::Context->config('smspass');
+my $uri ="https://spgw.kktcell.com/smshttpproxy/SmsHttpProxyServlet";
+
+
+
+ at ISA = qw(Exporter);
+
+ at EXPORT = qw(
+&get_sms_auth
+&send_sms
+&read_sms
+&error_codes
+&parse_phone
+&parse_message
+&write_sms
+&mod_sms
+&kill_sms
+);
+
+sub get_sms_auth {
+ my $ua = LWP::UserAgent->new;
+my $commands;
+ my $res=$ua->post($uri,[cmd=>'REGISTER',pUser=>$user,pPwd=>$pwd]);
+ if ($res->is_success){
+ $commands=parse_content($res->content);
+ }
+return($commands,$ua);
+}
+
+sub send_sms{
+my $ua=shift;
+my $phone=shift;
+my $message=shift;
+my $session=shift;
+ my $res=$ua->post($uri,[cmd=>'SENDSMS',pUser=>$user,pPwd=>$pwd,pSessionId=>$session,pService_Code=>4130,pMsisdn=>$phone,
+ pContent=>$message]);
+return parse_content($res->content);
+}
+sub read_sms{
+my $ua=shift;
+my $session=shift;
+ my $res=$ua->post($uri,[cmd=>'GETSMS',pUser=>$user,pPwd=>$pwd,pSessionId=>$session,pService_Code=>4130]);
+return parse_content($res->content);
+}
+sub parse_content{
+my $content=shift;
+my %commands;
+my @attributes=split /&/,$content;
+ foreach my $params(@attributes){
+ my (@param)=split /=/,$params;
+ $commands{$param[0]}=$param[1];
+ }
+return(\%commands);
+}
+
+sub error_codes{
+my $error=shift;
+if ($error==-1){
+return "Closed session - Retry ";
+}elsif($error==-2){
+return "Invalid session - Retry ";
+}elsif($error==-3){
+return "Invalid password" ;
+}elsif($error==-103){
+return "Invalid user";
+}elsif($error==-422){
+return "Invalid Parameter";
+}elsif($error==-426){
+return "User doesnt have permission to send message";
+}elsif($error==-700){
+return "No permission";
+}elsif($error==-801){
+return " Msdisn count differs-warn administartor";
+}elsif($error==-803){
+return "Content count differs from XSER count";
+}elsif($error==-1101){
+return " Insufficient Credit Do not retry" ;
+}elsif($error==-1104){
+return "Invalid Phone number";
+}elsif($error==-10001){
+return " Internal system error- Tell Turkcell/Telsim";
+}elsif($error==-9005){
+return " No messages to read";
+}elsif ($error){
+return "Unknow error no $error occured - tell Turkcell/Telsim";
+}
+}
+
+sub parse_phone{
+## checks acceptable phone numbers
+## Fix to accept Telsim when available (542 numbers)
+my $phone=shift;
+$phone=~s/^0//g;
+$phone=~s/ //g;
+my $length=length($phone);
+if ($length==10 || $length==12){
+my $code=substr($phone,0,3) if $length==10;
+ $code=substr($phone,0,5) if $length==12;
+ if ($code=~/533/){
+ return $phone;
+ }else{
+ return 0;
+ }
+}else{
+return 0;
+}
+}
+
+sub parse_message{
+my $message=shift;
+$message=~s/ / /g;
+my @parsed=split / /,$message;
+return (@parsed);
+}
+
+sub write_sms{
+my ($userid,$message,$phone)=@_;
+my $dbh=C4::Context->dbh;
+my $sth=$dbh->prepare("INSERT into sms_messages(userid,message,user_phone,date_received) values(?,?,?,now())");
+$sth->execute($userid,$message,$phone);
+$sth->finish;
+return $dbh->{'mysql_insertid'};
+}
+
+sub mod_sms{
+my ($smsid,$message)=@_;
+my $dbh=C4::Context->dbh;
+my $sth=$dbh->prepare("UPDATE sms_messages set reply=? ,date_replied=now() where smsid=?");
+$sth->execute($message,$smsid);
+$sth->finish;
+}
+sub kill_sms{
+#end a session
+my $ua=shift;
+my $session=shift;
+ my $res=$ua->post($uri,[cmd=>'KILLSESSION',pSessionId=>$session]);
+}
+1;
+__END__
\ No newline at end of file
Index: Search.pm
===================================================================
RCS file: Search.pm
diff -N Search.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Search.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,1073 @@
+package C4::Search;
+
+# Copyright 2000-2002 Katipo Communications
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+require Exporter;
+use C4::Context;
+use C4::Reserves2;
+use C4::Biblio;
+use ZOOM;
+use Encode;
+use C4::Date;
+use Time::HiRes qw(gettimeofday tv_interval);
+
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
+
+# set the version for version checking
+$VERSION = do { my @v = '$Revision: 1.1.2.1 $' =~ /\d+/g;
+ shift(@v) . "." . join("_", map {sprintf "%03d", $_ } @v); };
+
+=head1 NAME
+
+C4::Search - Functions for searching the Koha catalog and other databases
+
+=head1 SYNOPSIS
+
+ use C4::Search;
+
+ my ($count, @results) = catalogsearch4($env, $type, $search, $num, $offset);
+
+=head1 DESCRIPTION
+
+This module provides the searching facilities for the Koha catalog and
+ZEBRA databases.
+
+
+
+=head1 FUNCTIONS
+
+=over 2
+
+=cut
+
+ at ISA = qw(Exporter);
+ at EXPORT = qw(
+ &barcodes &ItemInfo &itemcount
+ &getcoverPhoto &add_query_line
+ &FindDuplicate &ZEBRAsearch_kohafields &convertPQF &sqlsearch &cataloguing_search
+&getMARCnotes &getMARCsubjects &getMARCurls &getMARCadditional_authors &parsefields &spellSuggest);
+# make all your functions, whether exported or not;
+
+=head1
+ZEBRAsearchkohafields is the underlying API for searching zebra for KOHA internal use
+its kept similar to earlier version Koha Marc searches. instead of passing marc tags to the routine
+you pass named kohafields
+So you give an array of @kohafieldnames, at values, what relation they have @relations (equal, truncation etc) @and_or and
+you receive an array of XML records.
+The routine also has a flag $fordisplay and if it is set to 1 it will return the @results as an array of Perl hashes so that your previous
+search results templates do actually work.
+This routine will also take CCL,CQL or PQF queries and pass them straight to the server
+See sub FindDuplicates for an example;
+=cut
+
+
+
+
+sub ZEBRAsearch_kohafields{
+my ($kohafield,$value, $relation,$sort, $and_or, $fordisplay,$reorder,$startfrom,$number_of_results,$searchfrom,$searchtype)=@_;
+return (0,undef) unless (@$value[0]);
+
+my $server="biblioserver";
+my @results;
+my $attr;
+my $query;
+my $starttime;
+my $i;
+ unless($searchtype){
+ for ( $i=0; $i<=$#{$value}; $i++){
+ next if (@$value[$i] eq "");
+ my $keyattr=MARCfind_attr_from_kohafield(@$kohafield[$i]) if (@$kohafield[$i]);
+ if (!$keyattr){$keyattr=" \@attr 1=any";}
+ @$value[$i]=~ s/(\.|\?|\;|\=|\/|\\|\||\:|\*|\!|\,|\(|\)|\[|\]|\{|\}|\/|\")/ /g;
+ my $weighted=weightRank(@$kohafield[$i],@$value[$i],$i) unless($sort || $reorder);
+ $query.=$weighted.@$relation[$i]." ".$keyattr." \"".@$value[$i]."\" " if @$value[$i];
+ }
+ for (my $z= 0;$z<=$#{$and_or};$z++){
+ $query=@$and_or[$z]." ".$query if (@$value[$z+1] ne "");
+ }
+ }
+#warn $query;
+
+my @oConnection;
+($oConnection[0])=C4::Context->Zconn($server);
+my @sortpart;
+if ($reorder ){
+ (@sortpart)=split /,/,$reorder;
+}elsif ($sort){
+ (@sortpart)=split /,/,$sort;
+}
+if (@sortpart){
+##sortpart is expected to contain the form "title i<" notation or "title,1" both mean the same thing
+ if (@sortpart<2){
+ push @sortpart," "; ##In case multisort variable is coming as a single query
+ }
+ if ($sortpart[1]==2){
+ $sortpart[1]=">i"; ##Descending
+ }elsif ($sortpart[1]==1){
+ $sortpart[1]="<i"; ##Ascending
+ }
+}
+
+if ($searchtype){
+$query=convertPQF($searchtype,$oConnection[0],$value);
+}else{
+$query=new ZOOM::Query::PQF($query);
+}
+goto EXITING unless $query;## erronous query coming in
+$query->sortby($sortpart[0]." ".$sortpart[1]) if @sortpart;
+my $oResult;
+
+my $tried=0;
+
+my $numresults;
+
+retry:
+$starttime=[gettimeofday];
+$oResult= $oConnection[0]->search($query);
+my $i;
+my $event;
+ while (($i = ZOOM::event(\@oConnection)) != 0) {
+ $event = $oConnection[$i-1]->last_event();
+ last if $event == ZOOM::Event::ZEND;
+ }# while
+my $timetaken=sprintf("%.3f",tv_interval($starttime));
+ my($error, $errmsg, $addinfo, $diagset) = $oConnection[0]->error_x();
+ if ($error==10007 && $tried<3) {## timeout --another 30 looonng seconds for this update
+ $tried=$tried+1;
+ goto "retry";
+ }elsif ($error==2 && $tried<2) {## timeout --temporary zebra error !whatever that means
+ $tried=$tried+1;
+ goto "retry";
+ }elsif ($error){
+ warn "Error-$server /errcode:, $error, /MSG:,$errmsg,$addinfo \n";
+ $oResult->destroy();
+ $oConnection[0]->destroy();
+ return (undef,undef);
+ }
+my $dbh=C4::Context->dbh;
+ $numresults=$oResult->size() ;
+
+ if ($numresults>0){
+ my $ri=0;
+ my $z=0;
+
+ $ri=$startfrom if $startfrom;
+ for ( $ri; $ri<$numresults ; $ri++){
+
+ my $xmlrecord=$oResult->record($ri)->raw();
+ $xmlrecord=Encode::decode("utf8",$xmlrecord);
+ $xmlrecord=XML_xml2hash($xmlrecord);
+ $z++;
+
+ push @results,$xmlrecord;
+ last if ($number_of_results && $z>=$number_of_results);
+
+
+ }## for #numresults
+ if ($fordisplay){
+ my ($facets, at parsed)=parsefields($dbh,$searchfrom, at results);
+ $oResult->destroy();
+ $oConnection[0]->destroy();
+ $parsed[0]->{timetaken}=$timetaken;
+ return ($numresults,$facets, at parsed) ;
+ }
+ }# if numresults
+
+$oResult->destroy();
+$oConnection[0]->destroy();
+EXITING:
+return ($numresults, at results) ;
+}
+
+sub weightRank {
+my ($kohafield,$value,$i)=@_;
+### If a multi query is received weighting is reduced from 1st query being highest rank to last query being lowest;
+my $weighted;
+my $weight=1000 -($i*100);
+$weight=100 if $weight==0;
+ return "" if $value eq "";
+ my $keyattr=MARCfind_attr_from_kohafield($kohafield) if ($kohafield);
+ return "" if($keyattr=~/4=109/ || $keyattr=~/4=4/ || $keyattr=~/4=5/); ###ranked sort not valid for numeric fields
+ my $fullfield; ### not all indexes are Complete-field. Use only for title||author
+ if ($kohafield eq "title" || $kohafield eq "" || $kohafield eq "any"){
+ $keyattr=" \@attr 1=title-cover";
+ $fullfield="\@attr 6=3 ";
+ }elsif ($kohafield eq "author"){
+ $fullfield="\@attr 6=3 ";
+ }
+ $weighted.="\@attr 2=102 ".$keyattr." \@attr 3=1 $fullfield \@attr 9=$weight \"".$value."\" " ;
+ $weighted=" \@or ".$weighted;
+ return $weighted;
+}
+sub convertPQF{
+# Convert CCL, CQF or PQF to ZEBRA RPN queries,trap errors
+my ($search_type,$zconn,$query)=@_;
+my $pqf_query;
+if ($search_type eq "pqf"){
+eval{
+$pqf_query=new ZOOM::Query::PQF(@$query[0]);
+};
+}elsif ($search_type eq "ccl"){
+
+my $cclfile=C4::Context->config("ccl2rpn");
+$zconn->option(cclfile=>$cclfile);## CCL conversion file path
+eval{
+$pqf_query=new ZOOM::Query::CCL2RPN(@$query[0],$zconn);
+};
+}elsif ($search_type eq "cql"){
+eval{
+$pqf_query=new ZOOM::Query::CQL(@$query[0]);
+};
+}
+if ($@){
+$pqf_query=0;
+}
+
+return $pqf_query;
+}
+
+
+=item add_bold_fields
+After a search the searched keyword is <b>boldened</b> in the displayed search results if it exists in the title or author
+It is now depreceated
+=cut
+sub add_html_bold_fields {
+ my ($type, $data, $search) = @_;
+ foreach my $key ('title', 'author') {
+ my $new_key;
+
+ $new_key = 'bold_' . $key;
+ $data->{$new_key} = $data->{$key};
+ my $key1;
+
+ $key1 = $key;
+
+
+ my @keys;
+ my $i = 1;
+ if ($type eq 'keyword') {
+ my $newkey=$search->{'keyword'};
+ $newkey=~s /\++//g;
+ @keys = split " ", $newkey;
+ }
+ my $count = @keys;
+ for ($i = 0; $i < $count ; $i++) {
+
+ if (($data->{$new_key} =~ /($keys[$i])/i) && (lc($keys[$i]) ne 'b') ) {
+ my $word = $1;
+ $data->{$new_key} =~ s/$word/<b>$word<\/b>/;
+ }
+
+ }
+ }
+
+
+}
+ sub sqlsearch{
+## This searches the SQL database only for biblionumber,itemnumber,barcode
+### Not very useful on production but as a debug tool useful during system maturing for ZEBRA operations
+
+my ($dbh,$search)=@_;
+my $sth;
+if ($search->{'barcode'} ne '') {
+ $sth=$dbh->prepare("SELECT biblionumber from items where barcode=?");
+ $sth->execute($search->{'barcode'});
+}elsif ($search->{'itemnumber'} ne '') {
+ $sth=$dbh->prepare("SELECT biblionumber from items where itemnumber=?");
+ $sth->execute($search->{'itemnumber'});
+}elsif ($search->{'biblionumber'} ne '') {
+ $sth=$dbh->prepare("SELECT biblionumber from biblio where biblionumber=?");
+ $sth->execute($search->{'biblionumber'});
+}else{
+return (undef,undef);
+}
+
+ my $result=$sth->fetchrow_hashref;
+return (1,$result) if $result;
+}
+
+sub cataloguing_search{
+## This is an SQL based search designed to be used when adding a new biblio incase library sets
+## preference zebraorsql to sql when adding a new biblio
+my ($search,$num,$offset) = @_;
+ my ($count, at results);
+my $dbh=C4::Context->dbh;
+#Prepare search
+my $query;
+my $condition="select SQL_CALC_FOUND_ROWS marcxml from biblio where ";
+if ($search->{'isbn'} ne''){
+$search->{'isbn'}=$search->{'isbn'}."%";
+$query=$search->{'isbn'};
+$condition.= " isbn like ? ";
+}else{
+return (0,undef) unless $search->{title};
+$query=$search->{'title'};
+$condition.= " MATCH (title) AGAINST(? in BOOLEAN MODE ) ";
+}
+my $sth=$dbh->prepare($condition);
+$sth->execute($query);
+ my $nbresult=$dbh->prepare("SELECT FOUND_ROWS()");
+ $nbresult->execute;
+ my $count=$nbresult->fetchrow;
+my $limit = $num + $offset;
+my $startfrom = $offset;
+my $i=0;
+my @results;
+while (my $marc=$sth->fetchrow){
+ if (($i >= $startfrom) && ($i < $limit)) {
+ my $record=XML_xml2hash_onerecord($marc);
+ my $data=XMLmarc2koha_onerecord($dbh,$record,"biblios");
+ push @results,$data;
+ }
+$i++;
+last if $i==$limit;
+}
+return ($count, at results);
+}
+
+
+
+sub FindDuplicate {
+ my ($xml)=@_;
+my $dbh=C4::Context->dbh;
+ my ($result) = XMLmarc2koha_onerecord($dbh,$xml,"biblios");
+ my @kohafield;
+ my @value;
+ my @relation;
+ my @and_or;
+
+ # search duplicate on ISBN, easy and fast..
+
+ if ($result->{isbn}) {
+ push @kohafield,"isbn";
+###Temporary fix for ISBN
+my $isbn=$result->{isbn};
+$isbn=~ s/(\.|\?|\;|\=|\/|\\|\||\:|\!|\'|,|\-|\"|\*|\(|\)|\[|\]|\{|\}|\/)//g;
+ push @value,$isbn;
+ }else{
+$result->{title}=~s /\\//g;
+$result->{title}=~s /\"//g;
+$result->{title}=~ s/(\.|\?|\;|\=|\/|\\|\||\:|\*|\!|\,|\-|\(|\)|\[|\]|\{|\}|\/)/ /g;
+
+ push @kohafield,"title";
+ push @value,$result->{title};
+ push @relation,"\@attr 6=3 \@attr 4=1 \@attr 5=1"; ## right truncated,phrase,whole field
+
+ }
+ my ($total, at result)=ZEBRAsearch_kohafields(\@kohafield,\@value,\@relation,"",\@and_or,0,"",0,1);
+if ($total){
+my $title=XML_readline($result[0],"title","biblios") ;
+my $biblionumber=XML_readline($result[0],"biblionumber","biblios") ;
+ return $biblionumber,$title ;
+}
+
+}
+
+
+sub add_query_line {
+
+ my ($type,$search,$results)=@_;
+ my $dbh = C4::Context->dbh;
+ my $searchdesc = '';
+ my $from;
+ my $borrowernumber = $search->{'borrowernumber'};
+ my $remote_IP = $search->{'remote_IP'};
+ my $remote_URL= $search->{'remote_URL'};
+ my $searchdesc = $search->{'searchdesc'};
+
+my $sth = $dbh->prepare("INSERT INTO phrase_log(phr_phrase,phr_resultcount,phr_ip,user,actual) VALUES(?,?,?,?,?)");
+
+
+$sth->execute($searchdesc,$results,$remote_IP,$borrowernumber,$remote_URL);
+$sth->finish;
+
+}
+
+
+=item ItemInfo
+
+ @results = &ItemInfo($env, $biblionumber, $type);
+
+Returns information about books with the given biblionumber.
+
+C<$type> may be either C<intra> or anything else. If it is not set to
+C<intra>, then the search will exclude lost, very overdue, and
+withdrawn items.
+
+C<$env> is ignored.
+
+C<&ItemInfo> returns a list of references-to-hash. Each element
+contains a number of keys. Most of them are table items from the
+C<biblio>, C<biblioitems>, C<items>, and C<itemtypes> tables in the
+Koha database. Other keys include:
+
+=over 4
+
+=item C<$data-E<gt>{branchname}>
+
+The name (not the code) of the branch to which the book belongs.
+
+=item C<$data-E<gt>{datelastseen}>
+
+This is simply C<items.datelastseen>, except that while the date is
+stored in YYYY-MM-DD format in the database, here it is converted to
+DD/MM/YYYY format. A NULL date is returned as C<//>.
+
+=item C<$data-E<gt>{datedue}>
+
+=item C<$data-E<gt>{class}>
+
+This is the concatenation of C<biblioitems.classification>, the book's
+Dewey code, and C<biblioitems.subclass>.
+
+=item C<$data-E<gt>{ocount}>
+
+I think this is the number of copies of the book available.
+
+=item C<$data-E<gt>{order}>
+
+If this is set, it is set to C<One Order>.
+
+=back
+
+=cut
+#'
+sub ItemInfo {
+ my ($dbh,$data) = @_;
+ my $i=0;
+ my @results;
+my ($date_due, $count_reserves);
+ my $datedue = '';
+ my $isth=$dbh->prepare("Select issues.*,borrowers.cardnumber from issues,borrowers where itemnumber = ? and returndate is null and issues.borrowernumber=borrowers.borrowernumber");
+ $isth->execute($data->{'itemnumber'});
+ if (my $idata=$isth->fetchrow_hashref){
+ $data->{borrowernumber} = $idata->{borrowernumber};
+ $data->{cardnumber} = $idata->{cardnumber};
+ $datedue = format_date($idata->{'date_due'});
+ }
+ if ($datedue eq '' || $datedue eq "0000-00-00"){
+ $datedue="";
+ my ($restype,$reserves)=C4::Reserves2::CheckReserves($data->{'itemnumber'});
+ if ($restype) {
+ $count_reserves = $restype;
+ }
+ }
+ $isth->finish;
+ #get branch information.....
+ my $bsth=$dbh->prepare("SELECT * FROM branches WHERE branchcode = ?");
+ $bsth->execute($data->{'holdingbranch'});
+ if (my $bdata=$bsth->fetchrow_hashref){
+ $data->{'branchname'} = $bdata->{'branchname'};
+ }
+
+ $data->{'datelastseen'}=format_date($data->{'datelastseen'});
+ $data->{'datedue'}=$datedue;
+ $data->{'count_reserves'} = $count_reserves;
+ # get notforloan complete status if applicable
+ my ($tagfield,$tagsub)=MARCfind_marc_from_kohafield("notforloan","holdings");
+ my $sthnflstatus = $dbh->prepare("select authorised_value from holdings_subfield_structure where tagfield='$tagfield' and tagsubfield='$tagsub'");
+ $sthnflstatus->execute;
+ my ($authorised_valuecode) = $sthnflstatus->fetchrow;
+ if ($authorised_valuecode) {
+ $sthnflstatus = $dbh->prepare("select lib from authorised_values where category=? and authorised_value=?");
+ $sthnflstatus->execute($authorised_valuecode,$data->{itemnotforloan});
+ my ($lib) = $sthnflstatus->fetchrow;
+ $data->{notforloan} = $lib;
+ }
+
+# my shelf procedures
+ my ($tagfield,$tagsubfield)=MARCfind_marc_from_kohafield("shelf","holdings");
+
+ my $shelfstatus = $dbh->prepare("select authorised_value from holdings_subfield_structure where tagfield='$tagfield' and tagsubfield='$tagsubfield'");
+$shelfstatus->execute;
+ $authorised_valuecode = $shelfstatus->fetchrow;
+ if ($authorised_valuecode) {
+ $shelfstatus = $dbh->prepare("select lib from authorised_values where category=? and authorised_value=?");
+ $shelfstatus->execute($authorised_valuecode,$data->{shelf});
+
+ my ($lib) = $shelfstatus->fetchrow;
+ $data->{shelf} = $lib;
+ }
+
+
+
+ return($data);
+}
+
+
+
+
+
+=item barcodes
+
+ @barcodes = &barcodes($biblioitemnumber);
+
+Given a biblioitemnumber, looks up the corresponding items.
+
+Returns an array of references-to-hash; the keys are C<barcode> and
+C<itemlost>.
+
+The returned items include very overdue items, but not lost ones.
+
+=cut
+#'
+sub barcodes{
+ #called from request.pl
+ my ($biblionumber)=@_;
+#warn $biblionumber;
+ my $dbh = C4::Context->dbh;
+ my @kohafields;
+ my @values;
+ my @relations;
+ my $sort;
+ my @and_or;
+ my @fields;
+ push @kohafields, "biblionumber";
+ push @values,$biblionumber;
+ push @relations, " "," \@attr 2=1"; ## selecting wthdrawn less then 1
+ push @and_or, "\@and";
+ $sort="";
+ my ($count, at results)=ZEBRAsearch_kohafields(\@kohafields,\@values,\@relations,$sort,\@and_or,"","");
+push @fields,"barcode","itemlost","itemnumber","date_due","wthdrawn","notforloan";
+ my ($biblio, at items)=XMLmarc2koha($dbh,$results[0],"holdings", @fields);
+return(@items);
+}
+
+
+
+
+
+sub getMARCnotes {
+##Requires a MARCXML as $record
+ my ($dbh, $record, $marcflavour) = @_;
+
+ my ($mintag, $maxtag);
+ if (uc($marcflavour) eq uc"MARC21" || uc($marcflavour) eq "USMARC") {
+ $mintag = "500";
+ $maxtag = "599";
+ } else { # assume unimarc if not marc21
+ $mintag = "300";
+ $maxtag = "399";
+ }
+ my @marcnotes=();
+ my $marcnote;
+ foreach my $field ($mintag..$maxtag) {
+ my %line;
+ my @values=XML_readline_asarray($record,"","",$field,"");
+ foreach my $value (@values){
+ $marcnote = {MARCNOTE => $value,};
+ push @marcnotes, $marcnote;
+ }
+ }
+
+ my $marcnotesarray=\@marcnotes;
+ return $marcnotesarray;
+
+} # end getMARCnotes
+
+
+sub getMARCsubjects {
+
+ my ($dbh, $record, $marcflavour) = @_;
+ my ($mintag, $maxtag);
+ if (uc($marcflavour) eq uc"MARC21" || uc($marcflavour) eq "USMARC") {
+ $mintag = "600";
+ $maxtag = "699";
+ } else { # assume unimarc if not marc21
+ $mintag = "600";
+ $maxtag = "619";
+ }
+ my @marcsubjcts;
+ my $subjct = "";
+ my $subfield = "";
+ my $marcsubjct;
+
+ foreach my $field ($mintag..$maxtag) {
+ my @value =XML_readline_asarray($record,"","",$field,"a");
+ foreach my $subject (@value){
+ $marcsubjct = {MARCSUBJCT => $subject,};
+ push @marcsubjcts, $marcsubjct;
+ }
+
+ }
+ my $marcsubjctsarray=\@marcsubjcts;
+ return $marcsubjctsarray;
+} #end getMARCsubjects
+
+
+sub getMARCurls {
+ my ($dbh, $record, $marcflavour) = @_;
+ my ($mintag, $maxtag);
+ if (uc($marcflavour) eq uc"MARC21" || uc($marcflavour) eq "USMARC") {
+ $mintag = "856";
+ $maxtag = "856";
+ } else { # assume unimarc if not marc21
+ $mintag = "600";
+ $maxtag = "619";
+ }
+
+ my @marcurls;
+ my $url = "";
+ my $subfil = "";
+ my $marcurl;
+ my $value;
+ foreach my $field ($mintag..$maxtag) {
+ my @value =XML_readline_asarray($record,"","",$field,"u");
+ foreach my $url (@value){
+ if ( $value ne $url) {
+ $marcurl = {MARCURL => $url,};
+ push @marcurls, $marcurl;
+ $value=$url;
+ }
+ }
+ }
+
+
+ my $marcurlsarray=\@marcurls;
+ return $marcurlsarray;
+} #end getMARCurls
+
+sub getMARCadditional_authors {
+ my ($dbh, $record, $marcflavour) = @_;
+ my ($mintag, $maxtag);
+ if (uc($marcflavour) eq uc"MARC21" || uc($marcflavour) eq "USMARC") {
+ $mintag = "700";
+ $maxtag = "700";
+ } else { # assume unimarc if not marc21
+###FIX ME Correct tag to UNIMARC additional authors
+ $mintag = "200";
+ $maxtag = "200";
+ }
+
+ my @marcauthors;
+
+ my $subfil = "";
+ my $marcauth;
+ my $value;
+ foreach my $field ($mintag..$maxtag) {
+ my @value =XML_readline_asarray($record,"","",$field,"a");
+ foreach my $author (@value){
+ if ( $value ne $author) {
+ $marcauth = {MARCAUTHOR => $author,};
+ push @marcauthors, $marcauth;
+ $value=$author;
+ }
+ }
+ }
+
+
+ my $marcauthsarray=\@marcauthors;
+ return $marcauthsarray;
+} #end getMARCurls
+
+sub parsefields{
+#pass this a MARC record and it will parse it for display purposes
+my ($dbh,$intranet, at marcrecords)=@_;
+my @results;
+my @items;
+my $retrieve_from=C4::Context->preference('retrieve_from');
+#Build brancnames hash for displaying in OPAC - more user friendly
+#find branchname
+#get branch information.....
+my %branches;
+ my $bsth=$dbh->prepare("SELECT branchcode,branchname FROM branches");
+ $bsth->execute();
+ while (my $bdata=$bsth->fetchrow_hashref){
+ $branches{$bdata->{'branchcode'}}= $bdata->{'branchname'};
+ }
+
+#Building shelving hash if library has shelves defined like junior section, non-fiction, audio-visual room etc
+my %shelves;
+#find shelvingname
+my ($tagfield,$tagsubfield)=MARCfind_marc_from_kohafield("shelf","holdings");
+my $shelfstatus = $dbh->prepare("select authorised_value from holdings_subfield_structure where tagfield='$tagfield' and tagsubfield='$tagsubfield'");
+ $shelfstatus->execute;
+ my ($authorised_valuecode) = $shelfstatus->fetchrow;
+ if ($authorised_valuecode) {
+ $shelfstatus = $dbh->prepare("select lib,authorised_value from authorised_values where category=? ");
+ $shelfstatus->execute($authorised_valuecode);
+ while (my $lib = $shelfstatus->fetchrow_hashref){
+ $shelves{$lib->{'authorised_value'}} = $lib->{'lib'};
+ }
+ }
+my $even=1;
+### FACETED RESULTS
+ my $facets_counter = ();
+ my $facets_info = ();
+ my @facets_loop; # stores the ref to array of hashes for template
+
+foreach my $xml(@marcrecords){
+
+ if (C4::Context->preference('useFacets')){
+ ($facets_counter,$facets_info)=FillFacets($xml,$facets_counter,$facets_info);
+ }
+my @kohafields; ## just name those necessary for the result page
+push @kohafields, "biblionumber","title","author","publishercode","classification","subclass","itemtype","copyrightdate", "holdingbranch","date_due","location","shelf","itemcallnumber","notforloan","itemlost","wthdrawn","totalissue","coverphoto";
+my ($oldbiblio, at itemrecords) = XMLmarc2koha($dbh,$xml,"", at kohafields);
+my $bibliorecord;
+$oldbiblio->{totalissue}=sprintf("%4d",$oldbiblio->{totalissue});
+my %counts;
+
+$counts{'total'}=0;
+my $noitems = 1;
+my $norequests = 1;
+ ##Loop for each item field
+
+ foreach my $item (@itemrecords) {
+ $norequests = 0 unless $item->{'itemnotforloan'};
+ $noitems = 0;
+ my $status;
+ #renaming some fields according to templates
+ $item->{'branchname'}=$branches{$item->{'holdingbranch'}};
+ $item->{'shelves'}=$shelves{$item->{'shelf'}};
+ $status="Lost" if ($item->{'itemlost'}>0);
+ $status="Withdrawn" if ($item->{'wthdrawn'}>0);
+ if ($intranet eq "intranet"){ ## we give full itemcallnumber detail in intranet
+ $status="Due:".format_date($item->{'date_due'}) if ($item->{'date_due'} gt "0000-00-00");
+ $status = $item->{'holdingbranch'}."-".$item->{'shelf'}."[".$item->{'itemcallnumber'}."]" unless defined $status;
+ }else{
+ $status="On Loan" if ($item->{'date_due'} gt "0000-00-00");
+ $status = $item->{'branchname'}."[".$item->{'shelves'}."]" unless defined $status;
+ }
+
+ $counts{$status}++;
+ $counts{'total'}++;
+ }
+ $oldbiblio->{'noitems'} = $noitems;
+ $oldbiblio->{'norequests'} = $norequests;
+ $oldbiblio->{'even'} = $even;
+ $even= not $even;
+ if ($even){
+ $oldbiblio->{'toggle'}="#ffffcc";
+ } else {
+ $oldbiblio->{'toggle'}="white";
+ } ; ## some forms seems to use toggle
+
+ $oldbiblio->{'itemcount'} = $counts{'total'};
+ my $totalitemcounts = 0;
+ foreach my $key (keys %counts){
+ if ($key ne 'total'){
+ $totalitemcounts+= $counts{$key};
+ $oldbiblio->{'locationhash'}->{$key}=$counts{$key};
+
+ }
+ }
+ my ($locationtext, $locationtextonly, $notavailabletext) = ('','','');
+ foreach (sort keys %{$oldbiblio->{'locationhash'}}) {
+
+ if ($_ eq 'notavailable') {
+ $notavailabletext="Not available";
+ my $c=$oldbiblio->{'locationhash'}->{$_};
+ $oldbiblio->{'not-available-p'}=$c;
+ } else {
+ $locationtext.="$_";
+ my $c=$oldbiblio->{'locationhash'}->{$_};
+ if ($_ eq 'Lost') {
+ $oldbiblio->{'lost-p'} = $c;
+ } elsif ($_ eq 'Withdrawn') {
+ $oldbiblio->{'withdrawn-p'} = $c;
+ } elsif ($_ =~/\^Due:/) {
+
+ $oldbiblio->{'on-loan-p'} = $c;
+ } else {
+ $locationtextonly.= $_;
+ $locationtextonly.= " ($c)<br> " if $totalitemcounts > 1;
+ }
+ if ($totalitemcounts>1) {
+ $locationtext.=" ($c)<br> ";
+ }
+ }
+ }
+ if ($notavailabletext) {
+ $locationtext.= $notavailabletext;
+ } else {
+ $locationtext=~s/, $//;
+ }
+ $oldbiblio->{'location'} = $locationtext;
+ $oldbiblio->{'location-only'} = $locationtextonly;
+ $oldbiblio->{'use-location-flags-p'} = 1;
+ push @results,$oldbiblio;
+
+}## For each record received
+ at facets_loop=BuildFacets($facets_counter,$facets_info,%branches);
+
+ return(@facets_loop, at results);
+}
+
+sub FillFacets{
+my ($facet_record,$facets_counter,$facets_info)=@_;
+ my $facets = C4::Koha::getFacets();
+ for (my $k=0; $k<@$facets;$k++) {
+ my $tags=@$facets->[$k]->{tags};
+ my $subfields=@$facets->[$k]->{subfield};
+ my @fields;
+ for (my $i=0; $i<@$tags;$i++) {
+ my $type="biblios";
+ $type="holdings" if @$facets->[$k]->{'link_value'} =~/branch/; ## if using other facets from items add them here
+ if ($type eq "holdings"){
+ ###Read each item record
+ my $holdings=$facet_record->{holdings}->[0]->{record};
+ foreach my $holding(@$holdings){
+ for (my $z=0; $z<@$subfields;$z++) {
+ my $data=XML_readline_onerecord($holding,"","holdings",@$tags[$i],@$subfields[$z]);
+ $facets_counter->{ @$facets->[$k]->{'link_value'} }->{ $data }++ if $data;
+ }
+ }
+ }else{
+ for (my $z=0; $z<@$subfields;$z++) {
+ my $data=XML_readline($facet_record,"","biblios",@$tags[$i],@$subfields[$z]);
+ $facets_counter->{ @$facets->[$k]->{'link_value'} }->{ $data }++ if $data;
+ }
+ }
+ }
+ $facets_info->{ @$facets->[$k]->{'link_value'} }->{ 'label_value' } = @$facets->[$k]->{'label_value'};
+ $facets_info->{ @$facets->[$k]->{'link_value'} }->{ 'expanded' } = @$facets->[$k]->{'expanded'};
+ }
+return ($facets_counter,$facets_info);
+}
+
+sub BuildFacets {
+my ($facets_counter, $facets_info,%branches) = @_;
+
+ my @facets_loop; # stores the ref to array of hashes for template
+# BUILD FACETS
+ foreach my $link_value ( sort { $facets_counter->{$b} <=> $facets_counter->{$a} } keys %$facets_counter) {
+ my $expandable;
+ my $number_of_facets;
+ my @this_facets_array;
+ foreach my $one_facet ( sort { $facets_counter->{ $link_value }->{$b} <=> $facets_counter->{ $link_value }->{$a} } keys %{$facets_counter->{$link_value}} ) {
+ $number_of_facets++;
+ if (($number_of_facets < 11) || ($facets_info->{ $link_value }->{ 'expanded'})) {
+
+ # sanitize the link value ), ( will cause errors with CCL
+ my $facet_link_value = $one_facet;
+ $facet_link_value =~ s/(\(|\))/ /g;
+
+ # fix the length that will display in the label
+ my $facet_label_value = $one_facet;
+ $facet_label_value = substr($one_facet,0,20)."..." unless length($facet_label_value)<=20;
+ # well, if it's a branch, label by the name, not the code
+ if ($link_value =~/branch/) {
+ $facet_label_value = $branches{$one_facet};
+ }
+
+ # but we're down with the whole label being in the link's title
+ my $facet_title_value = $one_facet;
+
+ push @this_facets_array ,
+ ( { facet_count => $facets_counter->{ $link_value }->{ $one_facet },
+ facet_label_value => $facet_label_value,
+ facet_title_value => $facet_title_value,
+ facet_link_value => $facet_link_value,
+ type_link_value => $link_value,
+ },
+ );
+ }## if $number_of_facets
+ }##for $one_facet
+ unless ($facets_info->{ $link_value }->{ 'expanded'}) {
+ $expandable=1 if ($number_of_facets > 10);
+ }
+ push @facets_loop,(
+ { type_link_value => $link_value,
+ type_id => $link_value."_id",
+ type_label => $facets_info->{ $link_value }->{ 'label_value' },
+ facets => \@this_facets_array,
+ expandable => $expandable,
+ expand => $link_value,
+ },
+ );
+
+ }
+return \@facets_loop;
+}
+
+
+sub getcoverPhoto {
+## return the address of a cover image if defined otherwise the amazon cover images
+ my $record =shift ;
+
+ my $image=XML_readline_onerecord($record,"coverphoto","biblios");
+ if ($image){
+ return $image;
+ }
+# if there is no image put the amazon cover image adress
+
+my $isbn=XML_readline_onerecord($record,"isbn","biblios");
+return "http://images.amazon.com/images/P/".$isbn.".01.MZZZZZZZ.jpg" if $isbn;
+}
+
+=item itemcount
+
+ ($count, $lcount, $nacount, $fcount, $scount, $lostcount,
+ $mending, $transit,$ocount) =
+ &itemcount($env, $biblionumber, $type);
+
+Counts the number of items with the given biblionumber, broken down by
+category.
+
+C<$env> is ignored.
+
+If C<$type> is not set to C<intra>, lost, very overdue, and withdrawn
+items will not be counted.
+
+C<&itemcount> returns a nine-element list:
+
+C<$count> is the total number of items with the given biblionumber.
+
+C<$lcount> is the number of items at the Levin branch.
+
+C<$nacount> is the number of items that are neither borrowed, lost,
+nor withdrawn (and are therefore presumably on a shelf somewhere).
+
+C<$fcount> is the number of items at the Foxton branch.
+
+C<$scount> is the number of items at the Shannon branch.
+
+C<$lostcount> is the number of lost and very overdue items.
+
+C<$mending> is the number of items at the Mending branch (being
+mended?).
+
+C<$transit> is the number of items at the Transit branch (in transit
+between branches?).
+
+C<$ocount> is the number of items that haven't arrived yet
+(aqorders.quantity - aqorders.quantityreceived).
+
+=cut
+#'
+
+
+
+sub itemcount {
+ my ($env,$bibnum,$type)=@_;
+ my $dbh = C4::Context->dbh;
+my @kohafield;
+my @value;
+my @relation;
+my @and_or;
+my $sort;
+ my $query="Select * from items where
+ biblionumber=? ";
+push @kohafield,"biblionumber";
+push @value,$bibnum;
+
+my ($total, at result)=ZEBRAsearch_kohafields(\@kohafield,\@value, \@relation,"", \@and_or, 0);## there is only one record no need for $num or $offset
+my @fields;## extract only the fields required
+push @fields,"itemnumber","itemlost","wthdrawn","holdingbranch","date_due";
+my ($biblio, at items)=XMLmarc2koha ($dbh,$result[0],"holdings",\@fields);
+ my $count=0;
+ my $lcount=0;
+ my $nacount=0;
+ my $fcount=0;
+ my $scount=0;
+ my $lostcount=0;
+ my $mending=0;
+ my $transit=0;
+ my $ocount=0;
+ foreach my $data(@items){
+ if ($type ne "intra"){
+ next if ($data->{itemlost} || $data->{wthdrawn});
+ } ## Probably trying to hide lost item from opac ?
+ $count++;
+
+## Now it seems we want to find those which are onloan
+
+
+ if ( $data->{date_due} gt "0000-00-00"){
+ $nacount++;
+ next;
+ }
+### The rest of this code is hardcoded for Foxtrot Shanon etc. We urgently need a global understanding of these terms--TG
+ if ($data->{'holdingbranch'} eq 'C' || $data->{'holdingbranch'} eq 'LT'){
+ $lcount++;
+ }
+ if ($data->{'holdingbranch'} eq 'F' || $data->{'holdingbranch'} eq 'FP'){
+ $fcount++;
+ }
+ if ($data->{'holdingbranch'} eq 'S' || $data->{'holdingbranch'} eq 'SP'){
+ $scount++;
+ }
+ if ($data->{'itemlost'} eq '1'){
+ $lostcount++;
+ }
+ if ($data->{'itemlost'} eq '2'){
+ $lostcount++;
+ }
+ if ($data->{'holdingbranch'} eq 'FM'){
+ $mending++;
+ }
+ if ($data->{'holdingbranch'} eq 'TR'){
+ $transit++;
+ }
+
+ }
+# if ($count == 0){
+ my $sth2=$dbh->prepare("Select * from aqorders where biblionumber=?");
+ $sth2->execute($bibnum);
+ if (my $data=$sth2->fetchrow_hashref){
+ $ocount=$data->{'quantity'} - $data->{'quantityreceived'};
+ }
+# $count+=$ocount;
+
+ return ($count,$lcount,$nacount,$fcount,$scount,$lostcount,$mending,$transit,$ocount);
+}
+
+sub spellSuggest {
+my ($kohafield,$value)=@_;
+ if (@$kohafield[0] eq "title" || @$kohafield[0] eq "author" || @$kohafield eq "subject"){
+## pass them through
+}else{
+ @$kohafield[0]="any";
+}
+my $kohaattr=MARCfind_attr_from_kohafield(@$kohafield[0]);
+@$value[0]=~ s/(\.|\?|\;|\=|\/|\\|\||\:|\*|\!|\,|\(|\)|\[|\]|\{|\}|\/)/ /g;
+my $query= $kohaattr." \@attr 6=3 \"".@$value[0]."\"";
+my @zconn;
+ $zconn[0]=C4::Context->Zconn("biblioserver");
+$zconn[0]->option(number=>5);
+my $result=$zconn[0]->scan_pqf($query);
+my $i;
+my $event;
+ while (($i = ZOOM::event(\@zconn)) != 0) {
+ $event = $zconn[$i-1]->last_event();
+ last if $event == ZOOM::Event::ZEND;
+ }# whilemy $i;
+
+my $n=$result->size();
+
+my @suggestion;
+for (my $i=0; $i<$n; $i++){
+my ($term,$occ)=$result->term($i);
+push @suggestion, {kohafield=>@$kohafield[0], value=>$term,occ=>$occ} unless $term=~/\@/;
+}
+$zconn[0]->destroy();
+return @suggestion;
+}
+
+1;
+__END__
+
+=back
+
+=head1 AUTHOR
+
+Koha Developement team <info at koha.org>
+# New functions to comply with ZEBRA search and new KOHA 3 XML API added 2006 Tumer Garip tgarip at neu.edu.tr
+
+=cut
Index: Serials-new.pm
===================================================================
RCS file: Serials-new.pm
diff -N Serials-new.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Serials-new.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,1792 @@
+package C4::Serials; #assumes C4/Serials.pm
+
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+# $Id: Serials-new.pm,v 1.1.2.1 2007/03/10 01:35:34 tgarip1957 Exp $
+
+use strict;
+use C4::Date;
+use Date::Calc qw(:all);
+use C4::Suggestions;
+use C4::Biblio;
+use C4::Search;
+use C4::Letters;
+require Exporter;
+
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
+
+# set the version for version checking
+$VERSION = do { my @v = '$Revision: 1.1.2.1 $' =~ /\d+/g;
+ shift(@v) . "." . join("_", map {sprintf "%03d", $_ } @v); };
+
+
+=head1 NAME
+
+C4::Serials - Give functions for serializing.
+
+=head1 SYNOPSIS
+
+ use C4::Serials;
+
+=head1 DESCRIPTION
+
+Give all XYZ functions
+
+=head1 FUNCTIONS
+
+=cut
+ at ISA = qw(Exporter);
+ at EXPORT = qw(
+ &NewSubscription &ModSubscription &DelSubscription &GetSubscriptions &GetSubscription
+ &CountSubscriptionFromBiblionumber &GetSubscriptionsFromBiblionumber
+ &GetFullSubscriptionsFromBiblionumber &GetNextSeq
+ &ModSubscriptionHistory &NewIssue
+ &GetSerials &GetLatestSerials &ModSerialStatus
+ &HasSubscriptionExpired &GetSubscriptionExpirationDate &ReNewSubscription
+ &GetSuppliersWithLateIssues &GetLateIssues &GetMissingIssues
+ &GetDistributedTo &SetDistributedto
+ &getroutinglist &delroutingmember &addroutingmember &reorder_members
+ &check_routing &getsupplierbyserialid &updateClaim &removeMissingIssue &abouttoexpire
+ &Get_Next_Date
+);
+
+=head2 GetSuppliersWithLateIssues
+
+=over 4
+
+%supplierlist = &GetSuppliersWithLateIssues
+
+this function get all suppliers with late issues.
+
+return :
+the supplierlist into a hash. this hash containts id & name of the supplier
+
+=back
+
+=cut
+sub GetSuppliersWithLateIssues {
+ my $dbh = C4::Context->dbh;
+ my $query = qq|
+ SELECT DISTINCT id, name
+ FROM subscription, serial
+ LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
+ WHERE subscription.subscriptionid = serial.subscriptionid
+ AND (planneddate < now() OR serial.STATUS = 3 OR serial.STATUS = 4)
+ |;
+ my $sth = $dbh->prepare($query);
+ $sth->execute;
+ my %supplierlist;
+ while (my ($id,$name) = $sth->fetchrow) {
+ $supplierlist{$id} = $name;
+ }
+ if(C4::Context->preference("RoutingSerials")){
+ $supplierlist{''} = "All Suppliers";
+ }
+ return %supplierlist;
+}
+
+=head2 GetLateIssues
+
+=over 4
+
+ at issuelist = &GetLateIssues($supplierid)
+
+this function select late issues on database
+
+return :
+the issuelist into an table. Each line of this table containts a ref to a hash which it containts
+name,title,planneddate,serialseq,serial.subscriptionid from tables : subscription, serial & biblio
+
+=back
+
+=cut
+sub GetLateIssues {
+ my ($supplierid) = shift;
+ my $dbh = C4::Context->dbh;
+ my $sth;
+ if ($supplierid) {
+ my $query = qq |
+ SELECT name,title,planneddate,serialseq,serial.subscriptionid
+ FROM subscription, serial, biblio
+ LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
+ WHERE subscription.subscriptionid = serial.subscriptionid
+ AND ((planneddate < now() AND serial.STATUS =1) OR serial.STATUS = 3)
+ AND subscription.aqbooksellerid=$supplierid
+ AND biblio.biblionumber = subscription.biblionumber
+ ORDER BY title
+ |;
+ $sth = $dbh->prepare($query);
+ } else {
+ my $query = qq|
+ SELECT name,title,planneddate,serialseq,serial.subscriptionid
+ FROM subscription, serial, biblio
+ LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
+ WHERE subscription.subscriptionid = serial.subscriptionid
+ AND ((planneddate < now() AND serial.STATUS =1) OR serial.STATUS = 3)
+ AND biblio.biblionumber = subscription.biblionumber
+ ORDER BY title
+ |;
+ $sth = $dbh->prepare($query);
+ }
+ $sth->execute;
+ my @issuelist;
+ my $last_title;
+ my $odd=0;
+ my $count=0;
+ while (my $line = $sth->fetchrow_hashref) {
+ $odd++ unless $line->{title} eq $last_title;
+ $line->{title} = "" if $line->{title} eq $last_title;
+ $last_title = $line->{title} if ($line->{title});
+ $line->{planneddate} = format_date($line->{planneddate});
+ $line->{'odd'} = 1 if $odd %2 ;
+ $count++;
+ push @issuelist,$line;
+ }
+ return $count, at issuelist;
+}
+
+=head2 GetSubscriptionHistoryFromSubscriptionId
+
+=over 4
+
+$sth = GetSubscriptionHistoryFromSubscriptionId()
+this function just prepare the SQL request.
+After this function, don't forget to execute it by using $sth->execute($subscriptionid)
+return :
+$sth = $dbh->prepare($query).
+
+=back
+
+=cut
+sub GetSubscriptionHistoryFromSubscriptionId() {
+ my $dbh = C4::Context->dbh;
+ my $query = qq|
+ SELECT *
+ FROM subscriptionhistory
+ WHERE subscriptionid = ?
+ |;
+ return $dbh->prepare($query);
+}
+
+=head2 GetSerialStatusFromSerialId
+
+=over 4
+
+$sth = GetSerialStatusFromSerialId();
+this function just prepare the SQL request.
+After this function, don't forget to execute it by using $sth->execute($serialid)
+return :
+$sth = $dbh->prepare($query).
+
+=back
+
+=cut
+sub GetSerialStatusFromSerialId(){
+ my $dbh = C4::Context->dbh;
+ my $query = qq|
+ SELECT status
+ FROM serial
+ WHERE serialid = ?
+ |;
+ return $dbh->prepare($query);
+}
+
+
+=head2 GetSubscription
+
+=over 4
+
+$subs = GetSubscription($subscriptionid)
+this function get the subscription which has $subscriptionid as id.
+return :
+a hashref. This hash containts
+subscription, subscriptionhistory, aqbudget.bookfundid, biblio.title
+
+=back
+
+=cut
+sub GetSubscription {
+ my ($subscriptionid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query =qq(
+ SELECT subscription.*,
+ subscriptionhistory.*,
+ aqbudget.bookfundid,
+ aqbooksellers.name AS aqbooksellername,
+ biblio.title AS bibliotitle
+ FROM subscription
+ LEFT JOIN subscriptionhistory ON subscription.subscriptionid=subscriptionhistory.subscriptionid
+ LEFT JOIN aqbudget ON subscription.aqbudgetid=aqbudget.aqbudgetid
+ LEFT JOIN aqbooksellers ON subscription.aqbooksellerid=aqbooksellers.id
+ LEFT JOIN biblio ON biblio.biblionumber=subscription.biblionumber
+ WHERE subscription.subscriptionid = ?
+ );
+ my $sth = $dbh->prepare($query);
+ $sth->execute($subscriptionid);
+ my $subs = $sth->fetchrow_hashref;
+ return $subs;
+}
+
+=head2 GetSubscriptionsFromBiblionumber
+
+=over 4
+
+\@res = GetSubscriptionsFromBiblionumber($biblionumber)
+this function get the subscription list. it reads on subscription table.
+return :
+table of subscription which has the biblionumber given on input arg.
+each line of this table is a hashref. All hashes containt
+planned, histstartdate,opacnote,missinglist,receivedlist,periodicity,status & enddate
+
+=back
+
+=cut
+sub GetSubscriptionsFromBiblionumber {
+ my ($biblionumber) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = qq(
+ SELECT subscription.*,
+ subscriptionhistory.*,
+ aqbudget.bookfundid,
+ aqbooksellers.name AS aqbooksellername,
+ biblio.title AS bibliotitle
+ FROM subscription
+ LEFT JOIN subscriptionhistory ON subscription.subscriptionid=subscriptionhistory.subscriptionid
+ LEFT JOIN aqbudget ON subscription.aqbudgetid=aqbudget.aqbudgetid
+ LEFT JOIN aqbooksellers ON subscription.aqbooksellerid=aqbooksellers.id
+ LEFT JOIN biblio ON biblio.biblionumber=subscription.biblionumber
+ WHERE subscription.biblionumber = ?
+ );
+ my $sth = $dbh->prepare($query);
+ $sth->execute($biblionumber);
+ my @res;
+ while (my $subs = $sth->fetchrow_hashref) {
+ $subs->{planneddate} = format_date($subs->{planneddate});
+ $subs->{publisheddate} = format_date($subs->{publisheddate});
+ $subs->{histstartdate} = format_date($subs->{histstartdate});
+ $subs->{opacnote} =~ s/\n/\<br\/\>/g;
+ $subs->{missinglist} =~ s/\n/\<br\/\>/g;
+ $subs->{receivedlist} =~ s/\n/\<br\/\>/g;
+ $subs->{"periodicity".$subs->{periodicity}} = 1;
+ $subs->{"status".$subs->{'status'}} = 1;
+ if ($subs->{enddate} eq '0000-00-00') {
+ $subs->{enddate}='';
+ } else {
+ $subs->{enddate} = format_date($subs->{enddate});
+ }
+ push @res,$subs;
+ }
+ return \@res;
+}
+=head2 GetFullSubscriptionsFromBiblionumber
+
+=over 4
+
+ \@res = GetFullSubscriptionsFromBiblionumber($biblionumber)
+ this function read on serial table.
+
+=back
+
+=cut
+sub GetFullSubscriptionsFromBiblionumber {
+ my ($biblionumber) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query=qq|
+ SELECT serial.serialseq,
+ serial.planneddate,
+ serial.publisheddate,
+ serial.status,
+ serial.notes,
+ year(serial.publisheddate) AS year,
+ aqbudget.bookfundid,aqbooksellers.name AS aqbooksellername,
+ biblio.title AS bibliotitle
+ FROM serial
+ LEFT JOIN subscription ON
+ (serial.subscriptionid=subscription.subscriptionid AND subscription.biblionumber=serial.biblionumber)
+ LEFT JOIN aqbudget ON subscription.aqbudgetid=aqbudget.aqbudgetid
+ LEFT JOIN aqbooksellers on subscription.aqbooksellerid=aqbooksellers.id
+ LEFT JOIN biblio on biblio.biblionumber=subscription.biblionumber
+ WHERE subscription.biblionumber = ?
+ ORDER BY year,serial.publisheddate,serial.subscriptionid,serial.planneddate
+ |;
+
+ my $sth = $dbh->prepare($query);
+ $sth->execute($biblionumber);
+ my @res;
+ my $year;
+ my $startdate;
+ my $aqbooksellername;
+ my $bibliotitle;
+ my @loopissues;
+ my $first;
+ my $previousnote="";
+ while (my $subs = $sth->fetchrow_hashref) {
+ ### BUG To FIX: When there is no published date, will create many null ids!!!
+
+ if ($year and ($year==$subs->{year})){
+ if ($first eq 1){$first=0;}
+ my $temp=$res[scalar(@res)-1]->{'serials'};
+ push @$temp,
+ {'publisheddate' =>format_date($subs->{'publisheddate'}),
+ 'planneddate' => format_date($subs->{'planneddate'}),
+ 'serialseq' => $subs->{'serialseq'},
+ "status".$subs->{'status'} => 1,
+ 'notes' => $subs->{'notes'} eq $previousnote?"":$subs->{notes},
+ };
+ } else {
+ $first=1 if (not $year);
+ $year= $subs->{'year'};
+ $startdate= format_date($subs->{'startdate'});
+ $aqbooksellername= $subs->{'aqbooksellername'};
+ $bibliotitle= $subs->{'bibliotitle'};
+ my @temp;
+ push @temp,
+ {'publisheddate' =>format_date($subs->{'publisheddate'}),
+ 'planneddate' => format_date($subs->{'planneddate'}),
+ 'serialseq' => $subs->{'serialseq'},
+ "status".$subs->{'status'} => 1,
+ 'notes' => $subs->{'notes'} eq $previousnote?"":$subs->{notes},
+ };
+
+ push @res,{
+ 'year'=>$year,
+ 'startdate'=>$startdate,
+ 'aqbooksellername'=>$aqbooksellername,
+ 'bibliotitle'=>$bibliotitle,
+ 'serials'=>\@temp,
+ 'first'=>$first
+ };
+ }
+ $previousnote=$subs->{notes};
+ }
+ return \@res;
+}
+
+
+=head2 GetSubscriptions
+
+=over 4
+
+ at results = GetSubscriptions($title,$ISSN,$biblionumber);
+this function get all subscriptions which has title like $title,ISSN like $ISSN and biblionumber like $biblionumber.
+return:
+a table of hashref. Each hash containt the subscription.
+
+=back
+
+=cut
+sub GetSubscriptions {
+ my ($title,$ISSN,$biblionumber,$supplierid) = @_;
+ return unless $title or $ISSN or $biblionumber or $supplierid;
+ my $dbh = C4::Context->dbh;
+ my $sth;
+ if ($biblionumber) {
+ my $query = qq(
+ SELECT subscription.subscriptionid,biblio.title,biblio.issn,subscription.notes,biblio.biblionumber
+ FROM subscription,biblio
+ WHERE biblio.biblionumber = subscription.biblionumber
+ AND biblio.biblionumber=?
+ ORDER BY title
+ );
+ $sth = $dbh->prepare($query);
+ $sth->execute($biblionumber);
+ } elsif ($ISSN and $title){
+ my $query = qq|
+ SELECT subscription.subscriptionid,biblio.title,biblio.issn,subscription.notes,biblio.biblionumber,aqbooksellerid
+ FROM subscription,biblio
+ WHERE biblio.biblionumber= subscription.biblionumber
+ AND (biblio.title LIKE ? or biblio.issn = ?)
+ ORDER BY title
+ |;
+ $sth = $dbh->prepare($query);
+ $sth->execute("%$title%",$ISSN);
+ } elsif ($ISSN){
+ my $query = qq(
+ SELECT subscription.subscriptionid,biblio.title,biblio.issn,subscription.notes,biblio.biblionumber,aqbooksellerid
+ FROM subscription,biblio
+ WHERE biblio.biblionumber=subscription.biblionumber
+ AND biblio.issn = ?
+ ORDER BY title
+ );
+ $sth = $dbh->prepare($query);
+ $sth->execute($ISSN);
+ }elsif ($supplierid){
+ my $query = qq(
+ SELECT subscription.subscriptionid,biblio.title,biblio.issn,subscription.notes,biblio.biblionumber,aqbooksellerid
+ FROM subscription,biblio
+ WHERE biblio.biblionumber=subscription.biblionumber
+ AND subscription.aqbooksellerid = ?
+ ORDER BY title
+ );
+ $sth = $dbh->prepare($query);
+ $sth->execute($supplierid);
+ } else {
+ my $query = qq(
+ SELECT subscription.subscriptionid,biblio.title,biblio.issn,subscription.notes,biblio.biblionumber,aqbooksellerid
+ FROM subscription,biblio
+ WHERE biblio.biblionumber=subscription.biblionumber
+ AND biblio.title LIKE ?
+ ORDER BY title
+ );
+ $sth = $dbh->prepare($query);
+ $sth->execute("%$title%");
+ }
+
+
+ my @results;
+ my $previoustitle="";
+ my $odd=1;
+ while (my $line = $sth->fetchrow_hashref) {
+ if ($previoustitle eq $line->{title}) {
+ $line->{title}="";
+ $line->{issn}="";
+ $line->{toggle} = 1 if $odd==1;
+ } else {
+ $previoustitle=$line->{title};
+ $odd=-$odd;
+ $line->{toggle} = 1 if $odd==1;
+ }
+ push @results, $line;
+ }
+ return @results;
+}
+
+=head2 GetSerials
+
+=over 4
+
+($totalissues, at serials) = GetSerials($subscriptionid);
+this function get every serial not arrived for a given subscription
+as well as the number of issues registered in the database (all types)
+this number is used to see if a subscription can be deleted (=it must have only 1 issue)
+
+=back
+
+=cut
+sub GetSerials {
+ my ($subscriptionid) = @_;
+ my $dbh = C4::Context->dbh;
+
+ my $counter=0;
+ my @serials;
+
+ # status = 2 is "arrived"
+ my $query = qq|
+ SELECT *
+ FROM serial
+ WHERE subscriptionid = ? AND status NOT IN (2,4,5)
+ |;
+ my $sth=$dbh->prepare($query);
+ $sth->execute($subscriptionid);
+ while(my $line = $sth->fetchrow_hashref) {
+ $line->{"status".$line->{status}} = 1; # fills a "statusX" value, used for template status select list
+ $line->{"publisheddate"} = format_date($line->{"publisheddate"});
+ $line->{"planneddate"} = format_date($line->{"planneddate"});
+ push @serials,$line;
+ }
+ # OK, now add the last 5 issues arrived/missing
+ my $query = qq|
+ SELECT *
+ FROM serial
+ WHERE subscriptionid = ?
+ AND (status in (2,4,5))
+ ORDER BY serialid DESC
+ |;
+ my $sth=$dbh->prepare($query);
+ $sth->execute($subscriptionid);
+ while((my $line = $sth->fetchrow_hashref) && $counter <5) {
+ $counter++;
+ $line->{"status".$line->{status}} = 1; # fills a "statusX" value, used for template status select list
+ $line->{"planneddate"} = format_date($line->{"planneddate"});
+ $line->{"publisheddate"} = format_date($line->{"publisheddate"});
+ push @serials,$line;
+ }
+ my $query = qq|
+ SELECT count(*)
+ FROM serial
+ WHERE subscriptionid=?
+ |;
+ $sth=$dbh->prepare($query);
+ $sth->execute($subscriptionid);
+ my ($totalissues) = $sth->fetchrow;
+ return ($totalissues, at serials);
+}
+
+=head2 GetLatestSerials
+
+=over 4
+
+\@serials = GetLatestSerials($subscriptionid,$limit)
+get the $limit's latest serials arrived or missing for a given subscription
+return :
+a ref to a table which it containts all of the latest serials stored into a hash.
+
+=back
+
+=cut
+sub GetLatestSerials {
+ my ($subscriptionid,$limit) = @_;
+ my $dbh = C4::Context->dbh;
+ # status = 2 is "arrived"
+ my $strsth=qq(
+ SELECT serialid,serialseq, status, planneddate
+ FROM serial
+ WHERE subscriptionid = ?
+ AND (status =2 or status=4)
+ ORDER BY planneddate DESC LIMIT 0,$limit
+ );
+ my $sth=$dbh->prepare($strsth);
+ $sth->execute($subscriptionid);
+ my @serials;
+ while(my $line = $sth->fetchrow_hashref) {
+ $line->{"status".$line->{status}} = 1; # fills a "statusX" value, used for template status select list
+ $line->{"planneddate"} = format_date($line->{"planneddate"});
+ push @serials,$line;
+ }
+# my $query = qq|
+# SELECT count(*)
+# FROM serial
+# WHERE subscriptionid=?
+# |;
+# $sth=$dbh->prepare($query);
+# $sth->execute($subscriptionid);
+# my ($totalissues) = $sth->fetchrow;
+ return \@serials;
+}
+
+=head2 GetDistributedTo
+
+=over 4
+
+$distributedto=GetDistributedTo($subscriptionid)
+This function select the old previous value of distributedto in the database.
+
+=back
+
+=cut
+sub GetDistributedTo {
+ my $dbh = C4::Context->dbh;
+ my $distributedto;
+ my $subscriptionid = @_;
+ my $query = qq|
+ SELECT distributedto
+ FROM subscription
+ WHERE subscriptionid=?
+ |;
+ my $sth = $dbh->prepare($query);
+ $sth->execute($subscriptionid);
+ return ($distributedto) = $sth->fetchrow;
+}
+
+=head2 GetNextSeq
+
+=over 4
+
+GetNextSeq($val)
+$val is a hashref containing all the attributes of the table 'subscription'
+This function get the next issue for the subscription given on input arg
+return:
+all the input params updated.
+
+=back
+
+=cut
+sub Get_Next_Seq {
+ my ($val) =@_;
+ my ($calculated,$newlastvalue1,$newlastvalue2,$newlastvalue3,$newinnerloop1,$newinnerloop2,$newinnerloop3);
+ $calculated = $val->{numberingmethod};
+# calculate the (expected) value of the next issue received.
+ $newlastvalue1 = $val->{lastvalue1};
+# check if we have to increase the new value.
+ $newinnerloop1 = $val->{innerloop1}+1;
+ $newinnerloop1=0 if ($newinnerloop1 >= $val->{every1});
+ $newlastvalue1 += $val->{add1} if ($newinnerloop1<1); # <1 to be true when 0 or empty.
+ $newlastvalue1=$val->{setto1} if ($newlastvalue1>$val->{whenmorethan1}); # reset counter if needed.
+ $calculated =~ s/\{X\}/$newlastvalue1/g;
+
+ $newlastvalue2 = $val->{lastvalue2};
+# check if we have to increase the new value.
+ $newinnerloop2 = $val->{innerloop2}+1;
+ $newinnerloop2=0 if ($newinnerloop2 >= $val->{every2});
+ $newlastvalue2 += $val->{add2} if ($newinnerloop2<1); # <1 to be true when 0 or empty.
+ $newlastvalue2=$val->{setto2} if ($newlastvalue2>$val->{whenmorethan2}); # reset counter if needed.
+ $calculated =~ s/\{Y\}/$newlastvalue2/g;
+
+ $newlastvalue3 = $val->{lastvalue3};
+# check if we have to increase the new value.
+ $newinnerloop3 = $val->{innerloop3}+1;
+ $newinnerloop3=0 if ($newinnerloop3 >= $val->{every3});
+ $newlastvalue3 += $val->{add3} if ($newinnerloop3<1); # <1 to be true when 0 or empty.
+ $newlastvalue3=$val->{setto3} if ($newlastvalue3>$val->{whenmorethan3}); # reset counter if needed.
+ $calculated =~ s/\{Z\}/$newlastvalue3/g;
+ return ($calculated,$newlastvalue1,$newlastvalue2,$newlastvalue3,$newinnerloop1,$newinnerloop2,$newinnerloop3);
+}
+
+
+sub GetNextSeq {
+ my ($val) =@_;
+ my ($calculated,$newlastvalue1,$newlastvalue2,$newlastvalue3,$newinnerloop1,$newinnerloop2,$newinnerloop3);
+ my $pattern = $val->{numberpattern};
+ my @seasons = ('nothing','Winter','Spring','Summer','Autumn');
+ my @southern_seasons = ('','Summer','Autumn','Winter','Spring');
+ $calculated = $val->{numberingmethod};
+ $newlastvalue1 = $val->{lastvalue1};
+ $newlastvalue2 = $val->{lastvalue2};
+ $newlastvalue3 = $val->{lastvalue3};
+ if($newlastvalue3 > 0){ # if x y and z columns are used
+ $newlastvalue3 = $newlastvalue3+1;
+ if($newlastvalue3 > $val->{whenmorethan3}){
+ $newlastvalue3 = $val->{setto3};
+ $newlastvalue2++;
+ if($newlastvalue2 > $val->{whenmorethan2}){
+ $newlastvalue1++;
+ $newlastvalue2 = $val->{setto2};
+ }
+ }
+ $calculated =~ s/\{X\}/$newlastvalue1/g;
+ if($pattern == 6){
+ if($val->{hemisphere} == 2){
+ my $newlastvalue2seq = $southern_seasons[$newlastvalue2];
+ $calculated =~ s/\{Y\}/$newlastvalue2seq/g;
+ } else {
+ my $newlastvalue2seq = $seasons[$newlastvalue2];
+ $calculated =~ s/\{Y\}/$newlastvalue2seq/g;
+ }
+ } else {
+ $calculated =~ s/\{Y\}/$newlastvalue2/g;
+ }
+ $calculated =~ s/\{Z\}/$newlastvalue3/g;
+ }
+ if($newlastvalue2 > 0 && $newlastvalue3 < 1){ # if x and y columns are used
+ $newlastvalue2 = $newlastvalue2+1;
+ if($newlastvalue2 > $val->{whenmorethan2}){
+ $newlastvalue2 = $val->{setto2};
+ $newlastvalue1++;
+ }
+ $calculated =~ s/\{X\}/$newlastvalue1/g;
+ if($pattern == 6){
+ if($val->{hemisphere} == 2){
+ my $newlastvalue2seq = $southern_seasons[$newlastvalue2];
+ $calculated =~ s/\{Y\}/$newlastvalue2seq/g;
+ } else {
+ my $newlastvalue2seq = $seasons[$newlastvalue2];
+ $calculated =~ s/\{Y\}/$newlastvalue2seq/g;
+ }
+ } else {
+ $calculated =~ s/\{Y\}/$newlastvalue2/g;
+ }
+ }
+ if($newlastvalue1 > 0 && $newlastvalue2 < 1 && $newlastvalue3 < 1){ # if column x only
+ $newlastvalue1 = $newlastvalue1+1;
+ if($newlastvalue1 > $val->{whenmorethan1}){
+ $newlastvalue1 = $val->{setto2};
+ }
+ $calculated =~ s/\{X\}/$newlastvalue1/g;
+ }
+ return ($calculated,$newlastvalue1,$newlastvalue2,$newlastvalue3);
+}
+
+
+=head2 GetNextDate
+
+=over 4
+
+$resultdate = GetNextDate($planneddate,$subscription)
+
+this function get the date after $planneddate.
+return:
+the date on ISO format.
+
+=back
+
+=cut
+
+=head2 GetSeq
+
+=over 4
+
+$calculated = GetSeq($val)
+$val is a hashref containing all the attributes of the table 'subscription'
+this function transforms {X},{Y},{Z} to 150,0,0 for example.
+return:
+the sequence in integer format
+
+=back
+
+=cut
+sub GetSeq {
+ my ($val) =@_;
+ my $calculated = $val->{numberingmethod};
+ my $x=$val->{'lastvalue1'};
+ $calculated =~ s/\{X\}/$x/g;
+ my $y=$val->{'lastvalue2'};
+ $calculated =~ s/\{Y\}/$y/g;
+ my $z=$val->{'lastvalue3'};
+ $calculated =~ s/\{Z\}/$z/g;
+ return $calculated;
+}
+
+=head2 GetSubscriptionExpirationDate
+
+=over 4
+
+$sensddate = GetSubscriptionExpirationDate($subscriptionid)
+
+this function return the expiration date for a subscription given on input args.
+
+return
+the enddate
+
+=back
+
+=cut
+sub GetSubscriptionExpirationDate {
+ my ($subscriptionid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $subscription = GetSubscription($subscriptionid);
+ my $enddate = $subscription->{startdate};
+
+# we don't do the same test if the subscription is based on X numbers or on X weeks/months
+# warn "SUBSCRIPTIONID :$subscriptionid";
+# use Data::Dumper; warn Dumper($subscription);
+
+ if ( $subscription->{numberlength} ) {
+ #calculate the date of the last issue.
+ my $length = $subscription->{numberlength};
+# warn "ENDDATE ".$enddate;
+ for ( my $i = 1 ; $i <= $length ; $i++ ) {
+ $enddate = GetNextDate( $enddate, $subscription );
+# warn "AFTER ENDDATE ".$enddate;
+ }
+ }
+ elsif ( $subscription->{monthlength} ){
+# warn "dateCHECKRESERV :".$subscription->{startdate};
+ my @date=split (/-/,$subscription->{startdate});
+ my @enddate = Add_Delta_YM($date[0],$date[1],$date[2],0,$subscription->{monthlength});
+ $enddate=sprintf("%04d-%02d-%02d",$enddate[0],$enddate[1],$enddate[2]);
+ } elsif ( $subscription->{weeklength} ){
+ my @date=split (/-/,$subscription->{startdate});
+
+ my @enddate = Add_Delta_Days($date[0],$date[1],$date[2],$subscription->{weeklength}*7);
+ $enddate=sprintf("%04d-%02d-%02d",$enddate[0],$enddate[1],$enddate[2]);
+ }
+# warn "date de fin :$enddate";
+ return $enddate;
+}
+
+=head2 CountSubscriptionFromBiblionumber
+
+=over 4
+
+$subscriptionsnumber = CountSubscriptionFromBiblionumber($biblionumber)
+this count the number of subscription for a biblionumber given.
+return :
+the number of subscriptions with biblionumber given on input arg.
+
+=back
+
+=cut
+sub CountSubscriptionFromBiblionumber {
+ my ($biblionumber) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = qq|
+ SELECT count(*)
+ FROM subscription
+ WHERE biblionumber=?
+ |;
+ my $sth = $dbh->prepare($query);
+ $sth->execute($biblionumber);
+ my $subscriptionsnumber = $sth->fetchrow;
+ return $subscriptionsnumber;
+}
+
+
+=head2 ModSubscriptionHistory
+
+=over 4
+
+ModSubscriptionHistory($subscriptionid,$histstartdate,$enddate,$receivedlist,$missinglist,$opacnote,$librariannote);
+
+this function modify the history of a subscription. Put your new values on input arg.
+
+=back
+
+=cut
+sub ModSubscriptionHistory {
+ my ($subscriptionid,$histstartdate,$enddate,$receivedlist,$missinglist,$opacnote,$librariannote)=@_;
+ my $dbh=C4::Context->dbh;
+ my $query = qq(
+ UPDATE subscriptionhistory
+ SET histstartdate=?,enddate=?,receivedlist=?,missinglist=?,opacnote=?,librariannote=?
+ WHERE subscriptionid=?
+ );
+ my $sth = $dbh->prepare($query);
+ $receivedlist =~ s/^,//g;
+ $missinglist =~ s/^,//g;
+ $opacnote =~ s/^,//g;
+ $sth->execute($histstartdate,$enddate,$receivedlist,$missinglist,$opacnote,$librariannote,$subscriptionid);
+}
+
+=head2 ModSerialStatus
+
+=over 4
+
+ModSerialStatus($serialid,$serialseq, $publisheddate,$planneddate,$status,$notes)
+
+This function modify the serial status. Serial status is a number.(eg 2 is "arrived")
+Note : if we change from "waited" to something else,then we will have to create a new "waited" entry
+
+=back
+
+=cut
+sub ModSerialStatus {
+ my ($serialid,$serialseq, $publisheddate,$planneddate,$status,$notes,$itemnumber)=@_;
+
+ # 1st, get previous status :
+ my $dbh = C4::Context->dbh;
+ my $query = qq|
+ SELECT subscriptionid,status
+ FROM serial
+ WHERE serialid=?
+ |;
+ my $sth = $dbh->prepare($query);
+ $sth->execute($serialid);
+ my ($subscriptionid,$oldstatus) = $sth->fetchrow;
+ # change status & update subscriptionhistory
+ if ($status eq 6){
+ DelIssue($serialseq, $subscriptionid)
+ } else {
+ my $query = qq(
+ UPDATE serial
+ SET serialseq=?,publisheddate=?,planneddate=?,status=?,notes=?,itemnumber=?
+ WHERE serialid = ?
+ );
+ $sth = $dbh->prepare($query);
+ $sth->execute($serialseq,format_date_in_iso($publisheddate),format_date_in_iso($planneddate),$status,$notes,$itemnumber,$serialid);
+ my $query = qq(
+ SELECT missinglist,receivedlist
+ FROM subscriptionhistory
+ WHERE subscriptionid=?
+ );
+ $sth = $dbh->prepare($query);
+ $sth->execute($subscriptionid);
+ my ($missinglist,$receivedlist) = $sth->fetchrow;
+ if ($status == 2 && $oldstatus != 2) {
+ $receivedlist .= ",$serialseq";
+ }
+ $missinglist .= ",$serialseq" if ($status eq 4) ;
+ $missinglist .= ",not issued $serialseq" if ($status eq 5);
+ my $query = qq(
+ UPDATE subscriptionhistory
+ SET receivedlist=?, missinglist=?
+ WHERE subscriptionid=?
+ );
+ $sth=$dbh->prepare($query);
+ $sth->execute($receivedlist,$missinglist,$subscriptionid);
+ }
+ # create new waited entry if needed (ie : was a "waited" and has changed)
+ if ($oldstatus eq 1 && $status ne 1) {
+ my $query = qq(
+ SELECT *
+ FROM subscription
+ WHERE subscriptionid = ?
+ );
+ $sth = $dbh->prepare($query);
+ $sth->execute($subscriptionid);
+ my $val = $sth->fetchrow_hashref;
+ # next issue number
+ my ($newserialseq,$newlastvalue1,$newlastvalue2,$newlastvalue3,$newinnerloop1,$newinnerloop2,$newinnerloop3) = GetNextSeq($val);
+ # next date (calculated from actual date & frequency parameters)
+ my $nextplanneddate = GetNextDate($planneddate,$val);
+ my $nextpublisheddate = GetNextDate($publisheddate,$val);
+ NewIssue($newserialseq, $subscriptionid, $val->{'biblionumber'}, 1, $nextpublisheddate,$nextplanneddate,0);
+ my $query = qq|
+ UPDATE subscription
+ SET lastvalue1=?, lastvalue2=?, lastvalue3=?,
+ innerloop1=?, innerloop2=?, innerloop3=?
+ WHERE subscriptionid = ?
+ |;
+ $sth = $dbh->prepare($query);
+ $sth->execute($newlastvalue1,$newlastvalue2,$newlastvalue3,$newinnerloop1,$newinnerloop2,$newinnerloop3,$subscriptionid);
+ }
+}
+
+=head2 ModSubscription
+
+=over 4
+
+this function modify a subscription. Put all new values on input args.
+
+=back
+
+=cut
+sub ModSubscription {
+ my ($auser,$aqbooksellerid,$cost,$aqbudgetid,$startdate,
+ $periodicity,$dow,$numberlength,$weeklength,$monthlength,
+ $add1,$every1,$whenmorethan1,$setto1,$lastvalue1,$innerloop1,
+ $add2,$every2,$whenmorethan2,$setto2,$lastvalue2,$innerloop2,
+ $add3,$every3,$whenmorethan3,$setto3,$lastvalue3,$innerloop3,
+ $numberingmethod, $status, $biblionumber, $notes, $letter, $subscriptionid,$irregularity,$hemisphere,$callnumber,$numberpattern,$publisheddate)= @_;
+ my $dbh = C4::Context->dbh;
+ my $query = qq|
+ UPDATE subscription
+ SET librarian=?, aqbooksellerid=?,cost=?,aqbudgetid=?,startdate=?,
+ periodicity=?,dow=?,numberlength=?,weeklength=?,monthlength=?,
+ add1=?,every1=?,whenmorethan1=?,setto1=?,lastvalue1=?,innerloop1=?,
+ add2=?,every2=?,whenmorethan2=?,setto2=?,lastvalue2=?,innerloop2=?,
+ add3=?,every3=?,whenmorethan3=?,setto3=?,lastvalue3=?,innerloop3=?,
+ numberingmethod=?, status=?, biblionumber=?, notes=?, letter=?,irregularity=?,hemisphere=?,callnumber=?,numberpattern=? ,publisheddate=?
+ WHERE subscriptionid = ?
+ |;
+ my $sth=$dbh->prepare($query);
+ $sth->execute($auser,$aqbooksellerid,$cost,$aqbudgetid,$startdate,
+ $periodicity,$dow,$numberlength,$weeklength,$monthlength,
+ $add1,$every1,$whenmorethan1,$setto1,$lastvalue1,$innerloop1,
+ $add2,$every2,$whenmorethan2,$setto2,$lastvalue2,$innerloop2,
+ $add3,$every3,$whenmorethan3,$setto3,$lastvalue3,$innerloop3,
+ $numberingmethod, $status, $biblionumber, $notes, $letter, $irregularity,$hemisphere,$callnumber,$numberpattern,$publisheddate,$subscriptionid);
+ $sth->finish;
+}
+
+
+=head2 NewSubscription
+
+=over 4
+
+$subscriptionid = &NewSubscription($auser,$aqbooksellerid,$cost,$aqbudgetid,$biblionumber,
+ $startdate,$periodicity,$dow,$numberlength,$weeklength,$monthlength,
+ $add1,$every1,$whenmorethan1,$setto1,$lastvalue1,$innerloop1,
+ $add2,$every2,$whenmorethan2,$setto2,$lastvalue2,$innerloop2,
+ $add3,$every3,$whenmorethan3,$setto3,$lastvalue3,$innerloop3,
+ $numberingmethod, $status, $notes)
+
+Create a new subscription with value given on input args.
+
+return :
+the id of this new subscription
+
+=back
+
+=cut
+sub NewSubscription {
+ my ($auser,$aqbooksellerid,$cost,$aqbudgetid,$biblionumber,
+ $startdate,$periodicity,$dow,$numberlength,$weeklength,$monthlength,
+ $add1,$every1,$whenmorethan1,$setto1,$lastvalue1,
+ $add2,$every2,$whenmorethan2,$setto2,$lastvalue2,
+ $add3,$every3,$whenmorethan3,$setto3,$lastvalue3,
+ $numberingmethod, $status, $notes, $letter,$irregularity,$hemisphere,$callnumber,$numberpattern,$publisheddate) = @_;
+
+ my $dbh = C4::Context->dbh;
+#save subscription (insert into database)
+ my $query = qq|
+ INSERT INTO subscription
+ (librarian,aqbooksellerid,cost,aqbudgetid,biblionumber,
+ startdate,periodicity,dow,numberlength,weeklength,monthlength,
+ add1,every1,whenmorethan1,setto1,lastvalue1,
+ add2,every2,whenmorethan2,setto2,lastvalue2,
+ add3,every3,whenmorethan3,setto3,lastvalue3,
+ numberingmethod, status, notes, letter,irregularity,hemisphere,callnumber,numberpattern,publisheddate)
+ VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
+ |;
+ my $sth=$dbh->prepare($query);
+ $sth->execute(
+ $auser,$aqbooksellerid,$cost,$aqbudgetid,$biblionumber,
+ format_date_in_iso($startdate),$periodicity,$dow,$numberlength,$weeklength,$monthlength,
+ $add1,$every1,$whenmorethan1,$setto1,$lastvalue1,
+ $add2,$every2,$whenmorethan2,$setto2,$lastvalue2,
+ $add3,$every3,$whenmorethan3,$setto3,$lastvalue3,
+ $numberingmethod, $status, $notes, $letter,$irregularity,$hemisphere,$callnumber,$numberpattern,format_date_in_iso($publisheddate));
+
+
+#then create the 1st waited number
+ my $subscriptionid = $dbh->{'mysql_insertid'};
+ my $enddate = GetSubscriptionExpirationDate($subscriptionid);
+ my $query = qq(
+ INSERT INTO subscriptionhistory
+ (biblionumber, subscriptionid, histstartdate, enddate, missinglist, receivedlist, opacnote, librariannote)
+ VALUES (?,?,?,?,?,?,?,?)
+ );
+ $sth = $dbh->prepare($query);
+ $sth->execute($biblionumber, $subscriptionid, format_date_in_iso($startdate), format_date_in_iso($enddate), "", "", "", $notes);
+## User may have subscriptionid stored in MARC so check and fill it
+my $record=XMLgetbiblio($dbh,$biblionumber);
+$record=XML_xml2hash_onerecord($record);
+XML_writeline( $record, "subscriptionid", $subscriptionid,"biblios" );
+my $frameworkcode=MARCfind_frameworkcode($dbh,$biblionumber);
+NEWmodbiblio($dbh,$biblionumber,$record,$frameworkcode);
+# reread subscription to get a hash (for calculation of the 1st issue number)
+ my $query = qq(
+ SELECT *
+ FROM subscription
+ WHERE subscriptionid = ?
+ );
+ $sth = $dbh->prepare($query);
+ $sth->execute($subscriptionid);
+ my $val = $sth->fetchrow_hashref;
+
+# calculate issue number
+ my $serialseq = GetSeq($val);
+ my $query = qq|
+ INSERT INTO serial
+ (serialseq,subscriptionid,biblionumber,status, planneddate,publisheddate)
+ VALUES (?,?,?,?,?,?)
+ |;
+
+ $sth = $dbh->prepare($query);
+ $sth->execute($serialseq, $subscriptionid, $val->{'biblionumber'}, 1, format_date_in_iso($startdate),format_date_in_iso($publisheddate));
+ return $subscriptionid;
+}
+
+
+=head2 ReNewSubscription
+
+=over 4
+
+ReNewSubscription($subscriptionid,$user,$startdate,$numberlength,$weeklength,$monthlength,$note)
+
+this function renew a subscription with values given on input args.
+
+=back
+
+=cut
+sub ReNewSubscription {
+ my ($subscriptionid,$user,$startdate,$numberlength,$weeklength,$monthlength,$note) = @_;
+ my $dbh = C4::Context->dbh;
+ my $subscription = GetSubscription($subscriptionid);
+ my $record=XMLgetbiblio($dbh,$subscription->{biblionumber});
+ $record=XML_xml2hash_onerecord($record);
+ my $biblio = XMLmarc2koha_onerecord($dbh,$record,"biblios");
+ NewSuggestion($user,$subscription->{bibliotitle},$biblio->{author},$biblio->{publishercode},$biblio->{note},'','','','','',$subscription->{biblionumber});
+ # renew subscription
+ my $query = qq|
+ UPDATE subscription
+ SET startdate=?,numberlength=?,weeklength=?,monthlength=?
+ WHERE subscriptionid=?
+ |;
+my $sth=$dbh->prepare($query);
+ $sth->execute(format_date_in_iso($startdate),$numberlength,$weeklength,$monthlength, $subscriptionid);
+}
+
+
+=head2 NewIssue
+
+=over 4
+
+NewIssue($serialseq,$subscriptionid,$biblionumber,$status, $publisheddate, $planneddate)
+
+Create a new issue stored on the database.
+Note : we have to update the receivedlist and missinglist on subscriptionhistory for this subscription.
+
+=back
+
+=cut
+sub NewIssue {
+ my ($serialseq,$subscriptionid,$biblionumber,$status, $publisheddate, $planneddate,$itemnumber) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = qq|
+ INSERT INTO serial
+ (serialseq,subscriptionid,biblionumber,status,publisheddate,planneddate,itemnumber)
+ VALUES (?,?,?,?,?,?,?)
+ |;
+ my $sth = $dbh->prepare($query);
+ $sth->execute($serialseq,$subscriptionid,$biblionumber,$status,format_date_in_iso($publisheddate), format_date_in_iso($planneddate),$itemnumber);
+
+ my $query = qq|
+ SELECT missinglist,receivedlist
+ FROM subscriptionhistory
+ WHERE subscriptionid=?
+ |;
+ $sth = $dbh->prepare($query);
+ $sth->execute($subscriptionid);
+ my ($missinglist,$receivedlist) = $sth->fetchrow;
+ if ($status eq 2) {
+ $receivedlist .= ",$serialseq";
+ }
+ if ($status eq 4) {
+ $missinglist .= ",$serialseq";
+ }
+ my $query = qq|
+ UPDATE subscriptionhistory
+ SET receivedlist=?, missinglist=?
+ WHERE subscriptionid=?
+ |;
+ $sth=$dbh->prepare($query);
+ $sth->execute($receivedlist,$missinglist,$subscriptionid);
+}
+
+=head2 serialchangestatus
+
+=over 4
+
+serialchangestatus($serialid,$serialseq,$planneddate,$status,$notes)
+
+Change the status of a serial issue.
+Note: this was the older subroutine
+
+=back
+
+=cut
+sub serialchangestatus {
+ my ($serialid,$serialseq,$planneddate,$status,$notes)=@_;
+ # 1st, get previous status : if we change from "waited" to something else, then we will have to create a new "waited" entry
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("select subscriptionid,status from serial where serialid=?");
+ $sth->execute($serialid);
+ my ($subscriptionid,$oldstatus) = $sth->fetchrow;
+ # change status & update subscriptionhistory
+ if ($status eq 6){
+ delissue($serialseq, $subscriptionid)
+ }else{
+ $sth = $dbh->prepare("update serial set serialseq=?,planneddate=?,status=?,notes=? where serialid = ?");
+ $sth->execute($serialseq,format_date_in_iso($planneddate),$status,$notes,$serialid);
+
+ $sth = $dbh->prepare("select missinglist,receivedlist from subscriptionhistory where subscriptionid=?");
+ $sth->execute($subscriptionid);
+ my ($missinglist,$receivedlist) = $sth->fetchrow;
+ if ($status eq 2) {
+ $receivedlist .= "| $serialseq";
+ $receivedlist =~ s/^\| //g;
+ }
+ $missinglist .= "| $serialseq" if ($status eq 4) ;
+ $missinglist .= "| not issued $serialseq" if ($status eq 5);
+ $missinglist =~ s/^\| //g;
+ $sth=$dbh->prepare("update subscriptionhistory set receivedlist=?, missinglist=? where subscriptionid=?");
+ $sth->execute($receivedlist,$missinglist,$subscriptionid);
+ }
+ # create new waited entry if needed (ie : was a "waited" and has changed)
+ if ($oldstatus eq 1 && $status ne 1) {
+ $sth = $dbh->prepare("select * from subscription where subscriptionid = ? ");
+ $sth->execute($subscriptionid);
+ my $val = $sth->fetchrow_hashref;
+ # next issue number
+ my ($newserialseq,$newlastvalue1,$newlastvalue2,$newlastvalue3) = New_Get_Next_Seq($val);
+ my $nextplanneddate = GetNextDate($planneddate,$val);
+ NewIssue($newserialseq, $subscriptionid, $val->{'biblionumber'}, 1, $nextplanneddate);
+ $sth = $dbh->prepare("update subscription set lastvalue1=?, lastvalue2=?,lastvalue3=? where subscriptionid = ?");
+ $sth->execute($newlastvalue1,$newlastvalue2,$newlastvalue3,$subscriptionid);
+ }
+ # check if an alert must be sent... (= a letter is defined & status became "arrived"
+ $sth = $dbh->prepare("select * from subscription where subscriptionid = ? ");
+ $sth->execute($subscriptionid);
+ my $subscription = $sth->fetchrow_hashref;
+ if ($subscription->{letter} && $status eq 2) {
+ sendalerts('issue',$subscription->{subscriptionid},$subscription->{letter});
+ }
+}
+
+
+
+
+=head2 HasSubscriptionExpired
+
+=over 4
+
+1 or 0 = HasSubscriptionExpired($subscriptionid)
+
+the subscription has expired when the next issue to arrive is out of subscription limit.
+
+return :
+1 if true, 0 if false.
+
+=back
+
+=cut
+sub HasSubscriptionExpired {
+ my ($subscriptionid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $subscription = GetSubscription($subscriptionid);
+ my $expirationdate = GetSubscriptionExpirationDate($subscriptionid);
+ my $query = qq|
+ SELECT max(planneddate)
+ FROM serial
+ WHERE subscriptionid=?
+ |;
+ my $sth = $dbh->prepare($query);
+ $sth->execute($subscriptionid);
+ my ($res) = $sth->fetchrow ;
+ my @res=split (/-/,$res);
+ my @endofsubscriptiondate=split(/-/,$expirationdate);
+ return 1 if ( (@endofsubscriptiondate && Delta_Days($res[0],$res[1],$res[2],
+ $endofsubscriptiondate[0],$endofsubscriptiondate[1],$endofsubscriptiondate[2]) <= 0)
+ || (!$res));
+ return 0;
+}
+
+=head2 SetDistributedto
+
+=over 4
+
+SetDistributedto($distributedto,$subscriptionid);
+This function update the value of distributedto for a subscription given on input arg.
+
+=back
+
+=cut
+sub SetDistributedto {
+ my ($distributedto,$subscriptionid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = qq|
+ UPDATE subscription
+ SET distributedto=?
+ WHERE subscriptionid=?
+ |;
+ my $sth = $dbh->prepare($query);
+ $sth->execute($distributedto,$subscriptionid);
+}
+
+=head2 DelSubscription
+
+=over 4
+
+DelSubscription($subscriptionid)
+this function delete the subscription which has $subscriptionid as id.
+
+=back
+
+=cut
+sub DelSubscription {
+ my ($subscriptionid,$biblionumber) = @_;
+ my $dbh = C4::Context->dbh;
+## User may have subscriptionid stored in MARC so check and remove it
+my $record=XMLgetbibliohash($dbh,$biblionumber);
+XML_writeline( $record, "subscriptionid", "","biblios" );
+my $frameworkcode=MARCfind_frameworkcode($dbh,$biblionumber);
+NEWmodbiblio($dbh,$biblionumber,$record,$frameworkcode);
+ $subscriptionid=$dbh->quote($subscriptionid);
+ $dbh->do("DELETE FROM subscription WHERE subscriptionid=$subscriptionid");
+ $dbh->do("DELETE FROM subscriptionhistory WHERE subscriptionid=$subscriptionid");
+ $dbh->do("DELETE FROM serial WHERE subscriptionid=$subscriptionid");
+
+}
+
+=head2 DelIssue
+
+=over 4
+
+DelIssue($serialseq,$subscriptionid)
+this function delete an issue which has $serialseq and $subscriptionid given on input arg.
+
+=back
+
+=cut
+sub DelIssue {
+ my ($serialseq,$subscriptionid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = qq|
+ DELETE FROM serial
+ WHERE serialseq= ?
+ AND subscriptionid= ?
+ |;
+ my $sth = $dbh->prepare($query);
+ $sth->execute($serialseq,$subscriptionid);
+}
+
+=head2 GetMissingIssues
+
+=over 4
+
+($count, at issuelist) = &GetMissingIssues($supplierid,$serialid)
+
+this function select missing issues on database - where serial.status = 4
+
+return :
+a count of the number of missing issues
+the issuelist into a table. Each line of this table containts a ref to a hash which it containts
+name,title,planneddate,serialseq,serial.subscriptionid from tables : subscription, serial & biblio
+
+=back
+
+=cut
+sub GetMissingIssues {
+ my ($supplierid,$serialid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth;
+ my $byserial='';
+ if($serialid) {
+ $byserial = "and serialid = ".$serialid;
+ }
+ if ($supplierid) {
+ $sth = $dbh->prepare("SELECT serialid,aqbooksellerid,name,title,planneddate,serialseq,serial.subscriptionid,claimdate
+ FROM subscription, serial, biblio
+ LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
+ WHERE subscription.subscriptionid = serial.subscriptionid AND
+ serial.STATUS = 4 and
+ subscription.aqbooksellerid=$supplierid and
+ biblio.biblionumber = subscription.biblionumber ".$byserial." order by title
+ ");
+ } else {
+ $sth = $dbh->prepare("SELECT serialid,aqbooksellerid,name,title,planneddate,serialseq,serial.subscriptionid,claimdate
+ FROM subscription, serial, biblio
+ LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
+ WHERE subscription.subscriptionid = serial.subscriptionid AND
+ serial.STATUS =4 and
+ biblio.biblionumber = subscription.biblionumber ".$byserial." order by title
+ ");
+ }
+ $sth->execute;
+ my @issuelist;
+ my $last_title;
+ my $odd=0;
+ my $count=0;
+ while (my $line = $sth->fetchrow_hashref) {
+ $odd++ unless $line->{title} eq $last_title;
+ $last_title = $line->{title} if ($line->{title});
+ $line->{planneddate} = format_date($line->{planneddate});
+ $line->{claimdate} = format_date($line->{claimdate});
+ $line->{'odd'} = 1 if $odd %2 ;
+ $count++;
+ push @issuelist,$line;
+ }
+ return $count, at issuelist;
+}
+
+=head2 removeMissingIssue
+
+=over 4
+
+removeMissingIssue($subscriptionid)
+
+this function removes an issue from being part of the missing string in
+subscriptionlist.missinglist column
+
+called when a missing issue is found from the statecollection.pl file
+
+=back
+
+=cut
+sub removeMissingIssue {
+ my ($sequence,$subscriptionid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("SELECT * FROM subscriptionhistory WHERE subscriptionid = ?");
+ $sth->execute($subscriptionid);
+ my $data = $sth->fetchrow_hashref;
+ my $missinglist = $data->{'missinglist'};
+ my $missinglistbefore = $missinglist;
+ # warn $missinglist." before";
+ $missinglist =~ s/($sequence)//;
+ # warn $missinglist." after";
+ if($missinglist ne $missinglistbefore){
+ $missinglist =~ s/\|\s\|/\|/g;
+ $missinglist =~ s/^\| //g;
+ $missinglist =~ s/\|$//g;
+ my $sth2= $dbh->prepare("UPDATE subscriptionhistory
+ SET missinglist = ?
+ WHERE subscriptionid = ?");
+ $sth2->execute($missinglist,$subscriptionid);
+ }
+}
+
+=head2 updateClaim
+
+=over 4
+
+&updateClaim($serialid)
+
+this function updates the time when a claim is issued for late/missing items
+
+called from claims.pl file
+
+=back
+
+=cut
+sub updateClaim {
+ my ($serialid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("UPDATE serial SET claimdate = now()
+ WHERE serialid = ?
+ ");
+ $sth->execute($serialid);
+}
+
+=head2 getsupplierbyserialid
+
+=over 4
+
+($result) = &getsupplierbyserialid($serialid)
+
+this function is used to find the supplier id given a serial id
+
+return :
+hashref containing serialid, subscriptionid, and aqbooksellerid
+
+=back
+
+=cut
+sub getsupplierbyserialid {
+ my ($serialid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("SELECT serialid, serial.subscriptionid, aqbooksellerid
+ FROM serial, subscription
+ WHERE serial.subscriptionid = subscription.subscriptionid
+ AND serialid = ?
+ ");
+ $sth->execute($serialid);
+ my $line = $sth->fetchrow_hashref;
+ my $result = $line->{'aqbooksellerid'};
+ return $result;
+}
+
+=head2 check_routing
+
+=over 4
+
+($result) = &check_routing($subscriptionid)
+
+this function checks to see if a serial has a routing list and returns the count of routingid
+used to show either an 'add' or 'edit' link
+=back
+
+=cut
+sub check_routing {
+ my ($subscriptionid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("SELECT count(routingid) routingids FROM subscriptionroutinglist, subscription
+ WHERE subscription.subscriptionid = subscriptionroutinglist.subscriptionid
+ AND subscription.subscriptionid = ? ORDER BY ranking ASC
+ ");
+ $sth->execute($subscriptionid);
+ my $line = $sth->fetchrow_hashref;
+ my $result = $line->{'routingids'};
+ return $result;
+}
+
+=head2 addroutingmember
+
+=over 4
+
+&addroutingmember($bornum,$subscriptionid)
+
+this function takes a borrowernumber and subscriptionid and add the member to the
+routing list for that serial subscription and gives them a rank on the list
+of either 1 or highest current rank + 1
+
+=back
+
+=cut
+sub addroutingmember {
+ my ($bornum,$subscriptionid) = @_;
+ my $rank;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("SELECT max(ranking) rank FROM subscriptionroutinglist WHERE subscriptionid = ?");
+ $sth->execute($subscriptionid);
+ while(my $line = $sth->fetchrow_hashref){
+ if($line->{'rank'}>0){
+ $rank = $line->{'rank'}+1;
+ } else {
+ $rank = 1;
+ }
+ }
+ $sth = $dbh->prepare("INSERT INTO subscriptionroutinglist VALUES (null,?,?,?,null)");
+ $sth->execute($subscriptionid,$bornum,$rank);
+}
+
+=head2 reorder_members
+
+=over 4
+
+&reorder_members($subscriptionid,$routingid,$rank)
+
+this function is used to reorder the routing list
+
+it takes the routingid of the member one wants to re-rank and the rank it is to move to
+- it gets all members on list puts their routingid's into an array
+- removes the one in the array that is $routingid
+- then reinjects $routingid at point indicated by $rank
+- then update the database with the routingids in the new order
+
+=back
+
+=cut
+sub reorder_members {
+ my ($subscriptionid,$routingid,$rank) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("SELECT * FROM subscriptionroutinglist WHERE subscriptionid = ? ORDER BY ranking ASC");
+ $sth->execute($subscriptionid);
+ my @result;
+ while(my $line = $sth->fetchrow_hashref){
+ push(@result,$line->{'routingid'});
+ }
+ # To find the matching index
+ my $i;
+ my $key = -1; # to allow for 0 being a valid response
+ for ($i = 0; $i < @result; $i++) {
+ if ($routingid == $result[$i]) {
+ $key = $i; # save the index
+ last;
+ }
+ }
+ # if index exists in array then move it to new position
+ if($key > -1 && $rank > 0){
+ my $new_rank = $rank-1; # $new_rank is what you want the new index to be in the array
+ my $moving_item = splice(@result, $key, 1);
+ splice(@result, $new_rank, 0, $moving_item);
+ }
+ for(my $j = 0; $j < @result; $j++){
+ my $sth = $dbh->prepare("UPDATE subscriptionroutinglist SET ranking = '" . ($j+1) . "' WHERE routingid = '". $result[$j]."'");
+ $sth->execute;
+ }
+}
+
+=head2 delroutingmember
+
+=over 4
+
+&delroutingmember($routingid,$subscriptionid)
+
+this function either deletes one member from routing list if $routingid exists otherwise
+deletes all members from the routing list
+
+=back
+
+=cut
+sub delroutingmember {
+ # if $routingid exists then deletes that row otherwise deletes all with $subscriptionid
+ my ($routingid,$subscriptionid) = @_;
+ my $dbh = C4::Context->dbh;
+ if($routingid){
+ my $sth = $dbh->prepare("DELETE FROM subscriptionroutinglist WHERE routingid = ?");
+ $sth->execute($routingid);
+ reorder_members($subscriptionid,$routingid);
+ } else {
+ my $sth = $dbh->prepare("DELETE FROM subscriptionroutinglist WHERE subscriptionid = ?");
+ $sth->execute($subscriptionid);
+ }
+}
+
+=head2 getroutinglist
+
+=over 4
+
+($count, at routinglist) = &getroutinglist($subscriptionid)
+
+this gets the info from the subscriptionroutinglist for $subscriptionid
+
+return :
+a count of the number of members on routinglist
+the routinglist into a table. Each line of this table containts a ref to a hash which containts
+routingid - a unique id, borrowernumber, ranking, and biblionumber of subscription
+
+=back
+
+=cut
+sub getroutinglist {
+ my ($subscriptionid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("SELECT routingid, borrowernumber,
+ ranking, biblionumber FROM subscriptionroutinglist, subscription
+ WHERE subscription.subscriptionid = subscriptionroutinglist.subscriptionid
+ AND subscription.subscriptionid = ? ORDER BY ranking ASC
+ ");
+ $sth->execute($subscriptionid);
+ my @routinglist;
+ my $count=0;
+ while (my $line = $sth->fetchrow_hashref) {
+ $count++;
+ push(@routinglist,$line);
+ }
+ return ($count, at routinglist);
+}
+
+=head2 abouttoexpire
+
+=over 4
+
+$result = &abouttoexpire($subscriptionid)
+
+this function alerts you to the penultimate issue for a serial subscription
+
+returns 1 - if this is the penultimate issue
+returns 0 - if not
+
+=back
+
+=cut
+
+sub abouttoexpire {
+ my ($subscriptionid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $subscription = GetSubscription($subscriptionid);
+ my $expirationdate = GetSubscriptionExpirationDate($subscriptionid);
+ my $sth =
+ $dbh->prepare(
+ "select max(planneddate) from serial where subscriptionid=?");
+ $sth->execute($subscriptionid);
+ my ($res) = $sth->fetchrow ;
+# warn "date expiration : ".$expirationdate." date courante ".$res;
+ my @res=split /-/,$res;
+ my @endofsubscriptiondate=split/-/,$expirationdate;
+ my $per = $subscription->{'periodicity'};
+ my $x;
+ if ( $per == 1 ) {$x=7;}
+ if ( $per == 2 ) {$x=7; }
+ if ( $per == 3 ) {$x=14;}
+ if ( $per == 4 ) { $x = 21; }
+ if ( $per == 5 ) { $x = 31; }
+ if ( $per == 6 ) { $x = 62; }
+ if ( $per == 7 || $per == 8 ) { $x = 93; }
+ if ( $per == 9 ) { $x = 190; }
+ if ( $per == 10 ) { $x = 365; }
+ if ( $per == 11 ) { $x = 730; }
+ my @datebeforeend=Add_Delta_Days( $endofsubscriptiondate[0],$endofsubscriptiondate[1],$endofsubscriptiondate[2],
+ - (3 * $x)) if (@endofsubscriptiondate);
+ # warn "DATE BEFORE END: $datebeforeend";
+ return 1 if ( @res &&
+ (@datebeforeend &&
+ Delta_Days($res[0],$res[1],$res[2],
+ $datebeforeend[0],$datebeforeend[1],$datebeforeend[2]) <= 0) &&
+ (@endofsubscriptiondate &&
+ Delta_Days($res[0],$res[1],$res[2],
+ $endofsubscriptiondate[0],$endofsubscriptiondate[1],$endofsubscriptiondate[2]) >= 0) );
+ return 0;
+}
+
+
+
+=head2 GetNextDate
+
+=over 4
+
+($resultdate) = &GetNextDate($planneddate,$subscription)
+
+this function takes the planneddate and will return the next issue's date and will skip dates if there
+exists an irregularity
+- eg if periodicity is monthly and $planneddate is 2007-02-10 but if March and April is to be
+skipped then the returned date will be 2007-05-10
+
+return :
+$resultdate - then next date in the sequence
+
+=back
+
+=cut
+sub GetNextDate {
+ my ( $planneddate, $subscription ) = @_;
+ my @irreg = split( /\,/, $subscription->{irregularity} );
+
+ #date supposed to be in ISO.
+
+ my ( $year, $month, $day ) = split(/-/, $planneddate);
+ $month=1 unless ($month);
+ $day=1 unless ($day);
+ my @resultdate;
+
+ # warn "DOW $dayofweek";
+ if ( $subscription->{periodicity} == 1 ) {
+ my $dayofweek = Day_of_Week( $year,$month, $day );
+ for ( my $i = 0 ; $i < @irreg ; $i++ ) {
+ $dayofweek = 0 if ( $dayofweek == 7 );
+ if ( in_array( ($dayofweek + 1), @irreg ) ) {
+ ($year,$month,$day) = Add_Delta_Days($year,$month, $day , 1 );
+ $dayofweek++;
+ }
+ }
+ @resultdate = Add_Delta_Days($year,$month, $day , 1 );
+ }
+ if ( $subscription->{periodicity} == 2 ) {
+ my ($wkno,$year) = Week_of_Year( $year,$month, $day );
+ for ( my $i = 0 ; $i < @irreg ; $i++ ) {
+ if ( $irreg[$i] == (($wkno!=51)?($wkno +1) % 52 :52)) {
+ ($year,$month,$day) = Add_Delta_Days($year,$month, $day , 7 );
+ $wkno=(($wkno!=51)?($wkno +1) % 52 :52);
+ }
+ }
+ @resultdate = Add_Delta_Days( $year,$month, $day, 7);
+ }
+ if ( $subscription->{periodicity} == 3 ) {
+ my ($wkno,$year) = Week_of_Year( $year,$month, $day );
+ for ( my $i = 0 ; $i < @irreg ; $i++ ) {
+ if ( $irreg[$i] == (($wkno!=50)?($wkno +2) % 52 :52)) {
+ ### BUGFIX was previously +1 ^
+ ($year,$month,$day) = Add_Delta_Days($year,$month, $day , 14 );
+ $wkno=(($wkno!=50)?($wkno +2) % 52 :52);
+ }
+ }
+ @resultdate = Add_Delta_Days($year,$month, $day , 14 );
+ }
+ if ( $subscription->{periodicity} == 4 ) {
+ my ($wkno,$year) = Week_of_Year( $year,$month, $day );
+ for ( my $i = 0 ; $i < @irreg ; $i++ ) {
+ if ( $irreg[$i] == (($wkno!=49)?($wkno +3) % 52 :52)) {
+ ($year,$month,$day) = Add_Delta_Days($year,$month, $day , 21 );
+ $wkno=(($wkno!=49)?($wkno +3) % 52 :52);
+ }
+ }
+ @resultdate = Add_Delta_Days($year,$month, $day , 21 );
+ }
+ my $tmpmonth=$month;
+ if ( $subscription->{periodicity} == 5 ) {
+ for ( my $i = 0 ; $i < @irreg ; $i++ ) {
+ if ( $irreg[$i] == (($tmpmonth!=11)?($tmpmonth +1) % 12 :12)) {
+ ($year,$month,$day) = Add_Delta_YMD($year,$month, $day ,0,1,0 );
+ $tmpmonth=(($tmpmonth!=11)?($tmpmonth +1) % 12 :12);
+ }
+ }
+ @resultdate = Add_Delta_YMD($year,$month, $day ,0,1,0 );
+ }
+ if ( $subscription->{periodicity} == 6 ) {
+ for ( my $i = 0 ; $i < @irreg ; $i++ ) {
+ if ( $irreg[$i] == (($tmpmonth!=10)?($tmpmonth +2) % 12 :12)) {
+ ($year,$month,$day) = Add_Delta_YMD($year,$month, $day ,0,2,0 );
+ $tmpmonth=(($tmpmonth!=10)?($tmpmonth + 2) % 12 :12);
+ }
+ }
+ @resultdate = Add_Delta_YMD($year,$month, $day, 0, 2,0 );
+ }
+ if ( $subscription->{periodicity} == 7 ) {
+ for ( my $i = 0 ; $i < @irreg ; $i++ ) {
+ if ( $irreg[$i] == (($tmpmonth!=9)?($tmpmonth +3) % 12 :12)) {
+ ($year,$month,$day) = Add_Delta_YMD($year,$month, $day, 0, 3,0 );
+ $tmpmonth=(($tmpmonth!=9)?($tmpmonth + 3) % 12 :12);
+ }
+ }
+ @resultdate = Add_Delta_YMD($year,$month, $day, 0, 3, 0);
+ }
+ if ( $subscription->{periodicity} == 8 ) {
+ for ( my $i = 0 ; $i < @irreg ; $i++ ) {
+ if ( $irreg[$i] == (($tmpmonth!=9)?($tmpmonth +3) % 12 :12)) {
+ ($year,$month,$day) = Add_Delta_YMD($year,$month, $day, 0, 3,0 );
+ $tmpmonth=(($tmpmonth!=9)?($tmpmonth + 3) % 12 :12);
+ }
+ }
+ @resultdate = Add_Delta_YMD($year,$month, $day, 0, 3, 0);
+ }
+ if ( $subscription->{periodicity} == 9 ) {
+ for ( my $i = 0 ; $i < @irreg ; $i++ ) {
+ if ( $irreg[$i] == (($tmpmonth!=9)?($tmpmonth +3) % 12 :12)) {
+ ### BUFIX Seems to need more Than One ?
+ ($year,$month,$day) = Add_Delta_YM($year,$month, $day, 0, 6 );
+ $tmpmonth=(($tmpmonth!=6)?($tmpmonth + 6) % 12 :12);
+ }
+ }
+ @resultdate = Add_Delta_YM($year,$month, $day, 0, 6);
+ }
+ if ( $subscription->{periodicity} == 10 ) {
+ @resultdate = Add_Delta_YM($year,$month, $day, 1, 0 );
+ }
+ if ( $subscription->{periodicity} == 11 ) {
+ @resultdate = Add_Delta_YM($year,$month, $day, 2, 0 );
+ }
+ my $resultdate=sprintf("%04d-%02d-%02d",$resultdate[0],$resultdate[1],$resultdate[2]);
+# warn "dateNEXTSEQ : ".$resultdate;
+ return "$resultdate";
+}
+
+
+
+1;
+__END__
Index: Serials.pm
===================================================================
RCS file: Serials.pm
diff -N Serials.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Serials.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,1818 @@
+package C4::Serials; #assumes C4/Serials.pm
+
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+# $Id: Serials.pm,v 1.1.2.1 2007/03/10 01:35:34 tgarip1957 Exp $
+
+use strict;
+use C4::Date;
+use C4::Suggestions;
+use C4::Biblio;
+use C4::Search;
+use C4::Letters;
+require Exporter;
+
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
+
+# set the version for version checking
+$VERSION = do { my @v = '$Revision: 1.1.2.1 $' =~ /\d+/g;
+ shift(@v) . "." . join("_", map {sprintf "%03d", $_ } @v); };
+
+
+=head1 NAME
+
+C4::Serials - Give functions for serializing.
+
+=head1 SYNOPSIS
+
+ use C4::Serials;
+
+=head1 DESCRIPTION
+
+Give all XYZ functions
+
+=head1 FUNCTIONS
+
+=cut
+ at ISA = qw(Exporter);
+ at EXPORT = qw(
+ &NewSubscription &ModSubscription &DelSubscription &GetSubscriptions &GetSubscription
+ &CountSubscriptionFromBiblionumber &GetSubscriptionsFromBiblionumber
+ &GetFullSubscriptionsFromBiblionumber &GetNextSeq
+ &ModSubscriptionHistory &NewIssue
+ &GetSerials &GetLatestSerials &ModSerialStatus
+ &HasSubscriptionExpired &GetSubscriptionExpirationDate &ReNewSubscription
+ &GetSuppliersWithLateIssues &GetLateIssues &GetMissingIssues
+ &GetDistributedTo &SetDistributedto
+ &getroutinglist &delroutingmember &addroutingmember &reorder_members
+ &check_routing &getsupplierbyserialid &updateClaim &removeMissingIssue &abouttoexpire
+ &Get_Next_Date
+);
+
+=head2 GetSuppliersWithLateIssues
+
+=over 4
+
+%supplierlist = &GetSuppliersWithLateIssues
+
+this function get all suppliers with late issues.
+
+return :
+the supplierlist into a hash. this hash containts id & name of the supplier
+
+=back
+
+=cut
+sub GetSuppliersWithLateIssues {
+ my $dbh = C4::Context->dbh;
+ my $query = qq|
+ SELECT DISTINCT id, name
+ FROM subscription, serial
+ LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
+ WHERE subscription.subscriptionid = serial.subscriptionid
+ AND (planneddate < now() OR serial.STATUS = 3 OR serial.STATUS = 4)
+ |;
+ my $sth = $dbh->prepare($query);
+ $sth->execute;
+ my %supplierlist;
+ while (my ($id,$name) = $sth->fetchrow) {
+ $supplierlist{$id} = $name;
+ }
+ if(C4::Context->preference("RoutingSerials")){
+ $supplierlist{''} = "All Suppliers";
+ }
+ return %supplierlist;
+}
+
+=head2 GetLateIssues
+
+=over 4
+
+ at issuelist = &GetLateIssues($supplierid)
+
+this function select late issues on database
+
+return :
+the issuelist into an table. Each line of this table containts a ref to a hash which it containts
+name,title,planneddate,serialseq,serial.subscriptionid from tables : subscription, serial & biblio
+
+=back
+
+=cut
+sub GetLateIssues {
+ my ($supplierid) = shift;
+ my $dbh = C4::Context->dbh;
+ my $sth;
+ if ($supplierid) {
+ my $query = qq |
+ SELECT name,title,planneddate,serialseq,serial.subscriptionid
+ FROM subscription, serial, biblio
+ LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
+ WHERE subscription.subscriptionid = serial.subscriptionid
+ AND ((planneddate < now() AND serial.STATUS =1) OR serial.STATUS = 3)
+ AND subscription.aqbooksellerid=$supplierid
+ AND biblio.biblionumber = subscription.biblionumber
+ ORDER BY title
+ |;
+ $sth = $dbh->prepare($query);
+ } else {
+ my $query = qq|
+ SELECT name,title,planneddate,serialseq,serial.subscriptionid
+ FROM subscription, serial, biblio
+ LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
+ WHERE subscription.subscriptionid = serial.subscriptionid
+ AND ((planneddate < now() AND serial.STATUS =1) OR serial.STATUS = 3)
+ AND biblio.biblionumber = subscription.biblionumber
+ ORDER BY title
+ |;
+ $sth = $dbh->prepare($query);
+ }
+ $sth->execute;
+ my @issuelist;
+ my $last_title;
+ my $odd=0;
+ my $count=0;
+ while (my $line = $sth->fetchrow_hashref) {
+ $odd++ unless $line->{title} eq $last_title;
+ $line->{title} = "" if $line->{title} eq $last_title;
+ $last_title = $line->{title} if ($line->{title});
+ $line->{planneddate} = format_date($line->{planneddate});
+ $line->{'odd'} = 1 if $odd %2 ;
+ $count++;
+ push @issuelist,$line;
+ }
+ return $count, at issuelist;
+}
+
+=head2 GetSubscriptionHistoryFromSubscriptionId
+
+=over 4
+
+$sth = GetSubscriptionHistoryFromSubscriptionId()
+this function just prepare the SQL request.
+After this function, don't forget to execute it by using $sth->execute($subscriptionid)
+return :
+$sth = $dbh->prepare($query).
+
+=back
+
+=cut
+sub GetSubscriptionHistoryFromSubscriptionId() {
+ my $dbh = C4::Context->dbh;
+ my $query = qq|
+ SELECT *
+ FROM subscriptionhistory
+ WHERE subscriptionid = ?
+ |;
+ return $dbh->prepare($query);
+}
+
+=head2 GetSerialStatusFromSerialId
+
+=over 4
+
+$sth = GetSerialStatusFromSerialId();
+this function just prepare the SQL request.
+After this function, don't forget to execute it by using $sth->execute($serialid)
+return :
+$sth = $dbh->prepare($query).
+
+=back
+
+=cut
+sub GetSerialStatusFromSerialId(){
+ my $dbh = C4::Context->dbh;
+ my $query = qq|
+ SELECT status
+ FROM serial
+ WHERE serialid = ?
+ |;
+ return $dbh->prepare($query);
+}
+
+
+=head2 GetSubscription
+
+=over 4
+
+$subs = GetSubscription($subscriptionid)
+this function get the subscription which has $subscriptionid as id.
+return :
+a hashref. This hash containts
+subscription, subscriptionhistory, aqbudget.bookfundid, biblio.title
+
+=back
+
+=cut
+sub GetSubscription {
+ my ($subscriptionid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query =qq(
+ SELECT subscription.*,
+ subscriptionhistory.*,
+ aqbudget.bookfundid,
+ aqbooksellers.name AS aqbooksellername,
+ biblio.title AS bibliotitle
+ FROM subscription
+ LEFT JOIN subscriptionhistory ON subscription.subscriptionid=subscriptionhistory.subscriptionid
+ LEFT JOIN aqbudget ON subscription.aqbudgetid=aqbudget.aqbudgetid
+ LEFT JOIN aqbooksellers ON subscription.aqbooksellerid=aqbooksellers.id
+ LEFT JOIN biblio ON biblio.biblionumber=subscription.biblionumber
+ WHERE subscription.subscriptionid = ?
+ );
+ my $sth = $dbh->prepare($query);
+ $sth->execute($subscriptionid);
+ my $subs = $sth->fetchrow_hashref;
+ return $subs;
+}
+
+=head2 GetSubscriptionsFromBiblionumber
+
+=over 4
+
+\@res = GetSubscriptionsFromBiblionumber($biblionumber)
+this function get the subscription list. it reads on subscription table.
+return :
+table of subscription which has the biblionumber given on input arg.
+each line of this table is a hashref. All hashes containt
+planned, histstartdate,opacnote,missinglist,receivedlist,periodicity,status & enddate
+
+=back
+
+=cut
+sub GetSubscriptionsFromBiblionumber {
+ my ($biblionumber) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = qq(
+ SELECT subscription.*,
+ subscriptionhistory.*,
+ aqbudget.bookfundid,
+ aqbooksellers.name AS aqbooksellername,
+ biblio.title AS bibliotitle
+ FROM subscription
+ LEFT JOIN subscriptionhistory ON subscription.subscriptionid=subscriptionhistory.subscriptionid
+ LEFT JOIN aqbudget ON subscription.aqbudgetid=aqbudget.aqbudgetid
+ LEFT JOIN aqbooksellers ON subscription.aqbooksellerid=aqbooksellers.id
+ LEFT JOIN biblio ON biblio.biblionumber=subscription.biblionumber
+ WHERE subscription.biblionumber = ?
+ );
+ my $sth = $dbh->prepare($query);
+ $sth->execute($biblionumber);
+ my @res;
+ while (my $subs = $sth->fetchrow_hashref) {
+ $subs->{planneddate} = format_date($subs->{planneddate});
+ $subs->{publisheddate} = format_date($subs->{publisheddate});
+ $subs->{histstartdate} = format_date($subs->{histstartdate});
+ $subs->{opacnote} =~ s/\n/\<br\/\>/g;
+ $subs->{missinglist} =~ s/\n/\<br\/\>/g;
+ $subs->{receivedlist} =~ s/\n/\<br\/\>/g;
+ $subs->{"periodicity".$subs->{periodicity}} = 1;
+ $subs->{"status".$subs->{'status'}} = 1;
+ if ($subs->{enddate} eq '0000-00-00') {
+ $subs->{enddate}='';
+ } else {
+ $subs->{enddate} = format_date($subs->{enddate});
+ }
+ push @res,$subs;
+ }
+ return \@res;
+}
+=head2 GetFullSubscriptionsFromBiblionumber
+
+=over 4
+
+ \@res = GetFullSubscriptionsFromBiblionumber($biblionumber)
+ this function read on serial table.
+
+=back
+
+=cut
+sub GetFullSubscriptionsFromBiblionumber {
+ my ($biblionumber) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query=qq|
+ SELECT serial.serialseq,
+ serial.planneddate,
+ serial.publisheddate,
+ serial.status,
+ serial.notes,
+ year(serial.publisheddate) AS year,
+ aqbudget.bookfundid,aqbooksellers.name AS aqbooksellername,
+ biblio.title AS bibliotitle
+ FROM serial
+ LEFT JOIN subscription ON
+ (serial.subscriptionid=subscription.subscriptionid AND subscription.biblionumber=serial.biblionumber)
+ LEFT JOIN aqbudget ON subscription.aqbudgetid=aqbudget.aqbudgetid
+ LEFT JOIN aqbooksellers on subscription.aqbooksellerid=aqbooksellers.id
+ LEFT JOIN biblio on biblio.biblionumber=subscription.biblionumber
+ WHERE subscription.biblionumber = ?
+ ORDER BY year,serial.publisheddate,serial.subscriptionid,serial.planneddate
+ |;
+
+ my $sth = $dbh->prepare($query);
+ $sth->execute($biblionumber);
+ my @res;
+ my $year;
+ my $startdate;
+ my $aqbooksellername;
+ my $bibliotitle;
+ my @loopissues;
+ my $first;
+ my $previousnote="";
+ while (my $subs = $sth->fetchrow_hashref) {
+ ### BUG To FIX: When there is no published date, will create many null ids!!!
+
+ if ($year and ($year==$subs->{year})){
+ if ($first eq 1){$first=0;}
+ my $temp=$res[scalar(@res)-1]->{'serials'};
+ push @$temp,
+ {'publisheddate' =>format_date($subs->{'publisheddate'}),
+ 'planneddate' => format_date($subs->{'planneddate'}),
+ 'serialseq' => $subs->{'serialseq'},
+ "status".$subs->{'status'} => 1,
+ 'notes' => $subs->{'notes'} eq $previousnote?"":$subs->{notes},
+ };
+ } else {
+ $first=1 if (not $year);
+ $year= $subs->{'year'};
+ $startdate= format_date($subs->{'startdate'});
+ $aqbooksellername= $subs->{'aqbooksellername'};
+ $bibliotitle= $subs->{'bibliotitle'};
+ my @temp;
+ push @temp,
+ {'publisheddate' =>format_date($subs->{'publisheddate'}),
+ 'planneddate' => format_date($subs->{'planneddate'}),
+ 'serialseq' => $subs->{'serialseq'},
+ "status".$subs->{'status'} => 1,
+ 'notes' => $subs->{'notes'} eq $previousnote?"":$subs->{notes},
+ };
+
+ push @res,{
+ 'year'=>$year,
+ 'startdate'=>$startdate,
+ 'aqbooksellername'=>$aqbooksellername,
+ 'bibliotitle'=>$bibliotitle,
+ 'serials'=>\@temp,
+ 'first'=>$first
+ };
+ }
+ $previousnote=$subs->{notes};
+ }
+ return \@res;
+}
+
+
+=head2 GetSubscriptions
+
+=over 4
+
+ at results = GetSubscriptions($title,$ISSN,$biblionumber);
+this function get all subscriptions which has title like $title,ISSN like $ISSN and biblionumber like $biblionumber.
+return:
+a table of hashref. Each hash containt the subscription.
+
+=back
+
+=cut
+sub GetSubscriptions {
+ my ($title,$ISSN,$biblionumber,$supplierid) = @_;
+ return unless $title or $ISSN or $biblionumber or $supplierid;
+ my $dbh = C4::Context->dbh;
+ my $sth;
+ if ($biblionumber) {
+ my $query = qq(
+ SELECT subscription.subscriptionid,biblio.title,biblio.issn,subscription.notes,biblio.biblionumber
+ FROM subscription,biblio
+ WHERE biblio.biblionumber = subscription.biblionumber
+ AND biblio.biblionumber=?
+ ORDER BY title
+ );
+ $sth = $dbh->prepare($query);
+ $sth->execute($biblionumber);
+ } elsif ($ISSN and $title){
+ my $query = qq|
+ SELECT subscription.subscriptionid,biblio.title,biblio.issn,subscription.notes,biblio.biblionumber,aqbooksellerid
+ FROM subscription,biblio
+ WHERE biblio.biblionumber= subscription.biblionumber
+ AND (biblio.title LIKE ? or biblio.issn = ?)
+ ORDER BY title
+ |;
+ $sth = $dbh->prepare($query);
+ $sth->execute("%$title%",$ISSN);
+ } elsif ($ISSN){
+ my $query = qq(
+ SELECT subscription.subscriptionid,biblio.title,biblio.issn,subscription.notes,biblio.biblionumber,aqbooksellerid
+ FROM subscription,biblio
+ WHERE biblio.biblionumber=subscription.biblionumber
+ AND biblio.issn = ?
+ ORDER BY title
+ );
+ $sth = $dbh->prepare($query);
+ $sth->execute($ISSN);
+ }elsif ($supplierid){
+ my $query = qq(
+ SELECT subscription.subscriptionid,biblio.title,biblio.issn,subscription.notes,biblio.biblionumber,aqbooksellerid
+ FROM subscription,biblio
+ WHERE biblio.biblionumber=subscription.biblionumber
+ AND subscription.aqbooksellerid = ?
+ ORDER BY title
+ );
+ $sth = $dbh->prepare($query);
+ $sth->execute($supplierid);
+ } else {
+ my $query = qq(
+ SELECT subscription.subscriptionid,biblio.title,biblio.issn,subscription.notes,biblio.biblionumber,aqbooksellerid
+ FROM subscription,biblio
+ WHERE biblio.biblionumber=subscription.biblionumber
+ AND biblio.title LIKE ?
+ ORDER BY title
+ );
+ $sth = $dbh->prepare($query);
+ $sth->execute("%$title%");
+ }
+
+
+ my @results;
+ my $previoustitle="";
+ my $odd=1;
+ while (my $line = $sth->fetchrow_hashref) {
+ if ($previoustitle eq $line->{title}) {
+ $line->{title}="";
+ $line->{issn}="";
+ $line->{toggle} = 1 if $odd==1;
+ } else {
+ $previoustitle=$line->{title};
+ $odd=-$odd;
+ $line->{toggle} = 1 if $odd==1;
+ }
+ push @results, $line;
+ }
+ return @results;
+}
+
+=head2 GetSerials
+
+=over 4
+
+($totalissues, at serials) = GetSerials($subscriptionid);
+this function get every serial not arrived for a given subscription
+as well as the number of issues registered in the database (all types)
+this number is used to see if a subscription can be deleted (=it must have only 1 issue)
+
+=back
+
+=cut
+sub GetSerials {
+ my ($subscriptionid) = @_;
+ my $dbh = C4::Context->dbh;
+
+ my $counter=0;
+ my @serials;
+
+ # status = 2 is "arrived"
+ my $query = qq|
+ SELECT *
+ FROM serial
+ WHERE subscriptionid = ? AND status NOT IN (2,4,5)
+ |;
+ my $sth=$dbh->prepare($query);
+ $sth->execute($subscriptionid);
+ while(my $line = $sth->fetchrow_hashref) {
+ $line->{"status".$line->{status}} = 1; # fills a "statusX" value, used for template status select list
+ $line->{"publisheddate"} = format_date($line->{"publisheddate"});
+ $line->{"planneddate"} = format_date($line->{"planneddate"});
+ push @serials,$line;
+ }
+ # OK, now add the last 5 issues arrived/missing
+ my $query = qq|
+ SELECT *
+ FROM serial
+ WHERE subscriptionid = ?
+ AND (status in (2,4,5))
+ ORDER BY serialid DESC
+ |;
+ my $sth=$dbh->prepare($query);
+ $sth->execute($subscriptionid);
+ while((my $line = $sth->fetchrow_hashref) && $counter <5) {
+ $counter++;
+ $line->{"status".$line->{status}} = 1; # fills a "statusX" value, used for template status select list
+ $line->{"planneddate"} = format_date($line->{"planneddate"});
+ $line->{"publisheddate"} = format_date($line->{"publisheddate"});
+ push @serials,$line;
+ }
+ my $query = qq|
+ SELECT count(*)
+ FROM serial
+ WHERE subscriptionid=?
+ |;
+ $sth=$dbh->prepare($query);
+ $sth->execute($subscriptionid);
+ my ($totalissues) = $sth->fetchrow;
+ return ($totalissues, at serials);
+}
+
+=head2 GetLatestSerials
+
+=over 4
+
+\@serials = GetLatestSerials($subscriptionid,$limit)
+get the $limit's latest serials arrived or missing for a given subscription
+return :
+a ref to a table which it containts all of the latest serials stored into a hash.
+
+=back
+
+=cut
+sub GetLatestSerials {
+ my ($subscriptionid,$limit) = @_;
+ my $dbh = C4::Context->dbh;
+ # status = 2 is "arrived"
+ my $strsth=qq(
+ SELECT serialid,serialseq, status, planneddate
+ FROM serial
+ WHERE subscriptionid = ?
+ AND (status =2 or status=4)
+ ORDER BY planneddate DESC LIMIT 0,$limit
+ );
+ my $sth=$dbh->prepare($strsth);
+ $sth->execute($subscriptionid);
+ my @serials;
+ while(my $line = $sth->fetchrow_hashref) {
+ $line->{"status".$line->{status}} = 1; # fills a "statusX" value, used for template status select list
+ $line->{"planneddate"} = format_date($line->{"planneddate"});
+ push @serials,$line;
+ }
+# my $query = qq|
+# SELECT count(*)
+# FROM serial
+# WHERE subscriptionid=?
+# |;
+# $sth=$dbh->prepare($query);
+# $sth->execute($subscriptionid);
+# my ($totalissues) = $sth->fetchrow;
+ return \@serials;
+}
+
+=head2 GetDistributedTo
+
+=over 4
+
+$distributedto=GetDistributedTo($subscriptionid)
+This function select the old previous value of distributedto in the database.
+
+=back
+
+=cut
+sub GetDistributedTo {
+ my $dbh = C4::Context->dbh;
+ my $distributedto;
+ my $subscriptionid = @_;
+ my $query = qq|
+ SELECT distributedto
+ FROM subscription
+ WHERE subscriptionid=?
+ |;
+ my $sth = $dbh->prepare($query);
+ $sth->execute($subscriptionid);
+ return ($distributedto) = $sth->fetchrow;
+}
+
+=head2 GetNextSeq
+
+=over 4
+
+GetNextSeq($val)
+$val is a hashref containing all the attributes of the table 'subscription'
+This function get the next issue for the subscription given on input arg
+return:
+all the input params updated.
+
+=back
+
+=cut
+sub Get_Next_Seq {
+ my ($val) =@_;
+ my ($calculated,$newlastvalue1,$newlastvalue2,$newlastvalue3,$newinnerloop1,$newinnerloop2,$newinnerloop3);
+ $calculated = $val->{numberingmethod};
+# calculate the (expected) value of the next issue received.
+ $newlastvalue1 = $val->{lastvalue1};
+# check if we have to increase the new value.
+ $newinnerloop1 = $val->{innerloop1}+1;
+ $newinnerloop1=0 if ($newinnerloop1 >= $val->{every1});
+ $newlastvalue1 += $val->{add1} if ($newinnerloop1<1); # <1 to be true when 0 or empty.
+ $newlastvalue1=$val->{setto1} if ($newlastvalue1>$val->{whenmorethan1}); # reset counter if needed.
+ $calculated =~ s/\{X\}/$newlastvalue1/g;
+
+ $newlastvalue2 = $val->{lastvalue2};
+# check if we have to increase the new value.
+ $newinnerloop2 = $val->{innerloop2}+1;
+ $newinnerloop2=0 if ($newinnerloop2 >= $val->{every2});
+ $newlastvalue2 += $val->{add2} if ($newinnerloop2<1); # <1 to be true when 0 or empty.
+ $newlastvalue2=$val->{setto2} if ($newlastvalue2>$val->{whenmorethan2}); # reset counter if needed.
+ $calculated =~ s/\{Y\}/$newlastvalue2/g;
+
+ $newlastvalue3 = $val->{lastvalue3};
+# check if we have to increase the new value.
+ $newinnerloop3 = $val->{innerloop3}+1;
+ $newinnerloop3=0 if ($newinnerloop3 >= $val->{every3});
+ $newlastvalue3 += $val->{add3} if ($newinnerloop3<1); # <1 to be true when 0 or empty.
+ $newlastvalue3=$val->{setto3} if ($newlastvalue3>$val->{whenmorethan3}); # reset counter if needed.
+ $calculated =~ s/\{Z\}/$newlastvalue3/g;
+ return ($calculated,$newlastvalue1,$newlastvalue2,$newlastvalue3,$newinnerloop1,$newinnerloop2,$newinnerloop3);
+}
+
+
+sub GetNextSeq {
+ my ($val) =@_;
+ my ($calculated,$newlastvalue1,$newlastvalue2,$newlastvalue3,$newinnerloop1,$newinnerloop2,$newinnerloop3);
+ my $pattern = $val->{numberpattern};
+ my @seasons = ('nothing','Winter','Spring','Summer','Autumn');
+ my @southern_seasons = ('','Summer','Autumn','Winter','Spring');
+ $calculated = $val->{numberingmethod};
+ $newlastvalue1 = $val->{lastvalue1};
+ $newlastvalue2 = $val->{lastvalue2};
+ $newlastvalue3 = $val->{lastvalue3};
+ if($newlastvalue3 > 0){ # if x y and z columns are used
+ $newlastvalue3 = $newlastvalue3+1;
+ if($newlastvalue3 > $val->{whenmorethan3}){
+ $newlastvalue3 = $val->{setto3};
+ $newlastvalue2++;
+ if($newlastvalue2 > $val->{whenmorethan2}){
+ $newlastvalue1++;
+ $newlastvalue2 = $val->{setto2};
+ }
+ }
+ $calculated =~ s/\{X\}/$newlastvalue1/g;
+ if($pattern == 6){
+ if($val->{hemisphere} == 2){
+ my $newlastvalue2seq = $southern_seasons[$newlastvalue2];
+ $calculated =~ s/\{Y\}/$newlastvalue2seq/g;
+ } else {
+ my $newlastvalue2seq = $seasons[$newlastvalue2];
+ $calculated =~ s/\{Y\}/$newlastvalue2seq/g;
+ }
+ } else {
+ $calculated =~ s/\{Y\}/$newlastvalue2/g;
+ }
+ $calculated =~ s/\{Z\}/$newlastvalue3/g;
+ }
+ if($newlastvalue2 > 0 && $newlastvalue3 < 1){ # if x and y columns are used
+ $newlastvalue2 = $newlastvalue2+1;
+ if($newlastvalue2 > $val->{whenmorethan2}){
+ $newlastvalue2 = $val->{setto2};
+ $newlastvalue1++;
+ }
+ $calculated =~ s/\{X\}/$newlastvalue1/g;
+ if($pattern == 6){
+ if($val->{hemisphere} == 2){
+ my $newlastvalue2seq = $southern_seasons[$newlastvalue2];
+ $calculated =~ s/\{Y\}/$newlastvalue2seq/g;
+ } else {
+ my $newlastvalue2seq = $seasons[$newlastvalue2];
+ $calculated =~ s/\{Y\}/$newlastvalue2seq/g;
+ }
+ } else {
+ $calculated =~ s/\{Y\}/$newlastvalue2/g;
+ }
+ }
+ if($newlastvalue1 > 0 && $newlastvalue2 < 1 && $newlastvalue3 < 1){ # if column x only
+ $newlastvalue1 = $newlastvalue1+1;
+ if($newlastvalue1 > $val->{whenmorethan1}){
+ $newlastvalue1 = $val->{setto2};
+ }
+ $calculated =~ s/\{X\}/$newlastvalue1/g;
+ }
+ return ($calculated,$newlastvalue1,$newlastvalue2,$newlastvalue3);
+}
+
+
+=head2 GetNextDate
+
+=over 4
+
+$resultdate = GetNextDate($planneddate,$subscription)
+
+this function get the date after $planneddate.
+return:
+the date on ISO format.
+
+=back
+
+=cut
+
+=head2 GetSeq
+
+=over 4
+
+$calculated = GetSeq($val)
+$val is a hashref containing all the attributes of the table 'subscription'
+this function transforms {X},{Y},{Z} to 150,0,0 for example.
+return:
+the sequence in integer format
+
+=back
+
+=cut
+sub GetSeq {
+ my ($val) =@_;
+ my $calculated = $val->{numberingmethod};
+ my $x=$val->{'lastvalue1'};
+ $calculated =~ s/\{X\}/$x/g;
+ my $y=$val->{'lastvalue2'};
+ $calculated =~ s/\{Y\}/$y/g;
+ my $z=$val->{'lastvalue3'};
+ $calculated =~ s/\{Z\}/$z/g;
+ return $calculated;
+}
+
+=head2 GetSubscriptionExpirationDate
+
+=over 4
+
+$sensddate = GetSubscriptionExpirationDate($subscriptionid)
+
+this function return the expiration date for a subscription given on input args.
+
+return
+the enddate
+
+=back
+
+=cut
+sub GetSubscriptionExpirationDate {
+ my ($subscriptionid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $subscription = GetSubscription($subscriptionid);
+ my $enddate=$subscription->{startdate};
+ # we don't do the same test if the subscription is based on X numbers or on X weeks/months
+ if ($subscription->{numberlength}) {
+ #calculate the date of the last issue.
+ for (my $i=1;$i<=$subscription->{numberlength};$i++) {
+ $enddate = GetNextDate($enddate,$subscription);
+ }
+ }
+ else {
+ my $duration;
+ $duration=get_duration($subscription->{monthlength}." months") if ($subscription->{monthlength});
+ $duration=get_duration($subscription->{weeklength}." weeks") if ($subscription->{weeklength});
+ $enddate = DATE_Add_Duration($subscription->{startdate},$duration) ;
+ }
+ return $enddate;
+}
+
+=head2 CountSubscriptionFromBiblionumber
+
+=over 4
+
+$subscriptionsnumber = CountSubscriptionFromBiblionumber($biblionumber)
+this count the number of subscription for a biblionumber given.
+return :
+the number of subscriptions with biblionumber given on input arg.
+
+=back
+
+=cut
+sub CountSubscriptionFromBiblionumber {
+ my ($biblionumber) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = qq|
+ SELECT count(*)
+ FROM subscription
+ WHERE biblionumber=?
+ |;
+ my $sth = $dbh->prepare($query);
+ $sth->execute($biblionumber);
+ my $subscriptionsnumber = $sth->fetchrow;
+ return $subscriptionsnumber;
+}
+
+
+=head2 ModSubscriptionHistory
+
+=over 4
+
+ModSubscriptionHistory($subscriptionid,$histstartdate,$enddate,$receivedlist,$missinglist,$opacnote,$librariannote);
+
+this function modify the history of a subscription. Put your new values on input arg.
+
+=back
+
+=cut
+sub ModSubscriptionHistory {
+ my ($subscriptionid,$histstartdate,$enddate,$receivedlist,$missinglist,$opacnote,$librariannote)=@_;
+ my $dbh=C4::Context->dbh;
+ my $query = qq(
+ UPDATE subscriptionhistory
+ SET histstartdate=?,enddate=?,receivedlist=?,missinglist=?,opacnote=?,librariannote=?
+ WHERE subscriptionid=?
+ );
+ my $sth = $dbh->prepare($query);
+ $receivedlist =~ s/^,//g;
+ $missinglist =~ s/^,//g;
+ $opacnote =~ s/^,//g;
+ $sth->execute($histstartdate,$enddate,$receivedlist,$missinglist,$opacnote,$librariannote,$subscriptionid);
+}
+
+=head2 ModSerialStatus
+
+=over 4
+
+ModSerialStatus($serialid,$serialseq, $publisheddate,$planneddate,$status,$notes)
+
+This function modify the serial status. Serial status is a number.(eg 2 is "arrived")
+Note : if we change from "waited" to something else,then we will have to create a new "waited" entry
+
+=back
+
+=cut
+sub ModSerialStatus {
+ my ($serialid,$serialseq, $publisheddate,$planneddate,$status,$notes,$itemnumber)=@_;
+
+ # 1st, get previous status :
+ my $dbh = C4::Context->dbh;
+ my $query = qq|
+ SELECT subscriptionid,status
+ FROM serial
+ WHERE serialid=?
+ |;
+ my $sth = $dbh->prepare($query);
+ $sth->execute($serialid);
+ my ($subscriptionid,$oldstatus) = $sth->fetchrow;
+ # change status & update subscriptionhistory
+ if ($status eq 6){
+ DelIssue($serialseq, $subscriptionid)
+ } else {
+ my $query = qq(
+ UPDATE serial
+ SET serialseq=?,publisheddate=?,planneddate=?,status=?,notes=?,itemnumber=?
+ WHERE serialid = ?
+ );
+ $sth = $dbh->prepare($query);
+ $sth->execute($serialseq,format_date_in_iso($publisheddate),format_date_in_iso($planneddate),$status,$notes,$itemnumber,$serialid);
+ my $query = qq(
+ SELECT missinglist,receivedlist
+ FROM subscriptionhistory
+ WHERE subscriptionid=?
+ );
+ $sth = $dbh->prepare($query);
+ $sth->execute($subscriptionid);
+ my ($missinglist,$receivedlist) = $sth->fetchrow;
+ if ($status == 2 && $oldstatus != 2) {
+ $receivedlist .= ",$serialseq";
+ }
+ $missinglist .= ",$serialseq" if ($status eq 4) ;
+ $missinglist .= ",not issued $serialseq" if ($status eq 5);
+ my $query = qq(
+ UPDATE subscriptionhistory
+ SET receivedlist=?, missinglist=?
+ WHERE subscriptionid=?
+ );
+ $sth=$dbh->prepare($query);
+ $sth->execute($receivedlist,$missinglist,$subscriptionid);
+ }
+ # create new waited entry if needed (ie : was a "waited" and has changed)
+ if ($oldstatus eq 1 && $status ne 1) {
+ my $query = qq(
+ SELECT *
+ FROM subscription
+ WHERE subscriptionid = ?
+ );
+ $sth = $dbh->prepare($query);
+ $sth->execute($subscriptionid);
+ my $val = $sth->fetchrow_hashref;
+ # next issue number
+ my ($newserialseq,$newlastvalue1,$newlastvalue2,$newlastvalue3,$newinnerloop1,$newinnerloop2,$newinnerloop3) = GetNextSeq($val);
+ # next date (calculated from actual date & frequency parameters)
+ my $nextplanneddate = GetNextDate($planneddate,$val);
+ my $nextpublisheddate = GetNextDate($publisheddate,$val);
+ NewIssue($newserialseq, $subscriptionid, $val->{'biblionumber'}, 1, $nextpublisheddate,$nextplanneddate,0);
+ my $query = qq|
+ UPDATE subscription
+ SET lastvalue1=?, lastvalue2=?, lastvalue3=?,
+ innerloop1=?, innerloop2=?, innerloop3=?
+ WHERE subscriptionid = ?
+ |;
+ $sth = $dbh->prepare($query);
+ $sth->execute($newlastvalue1,$newlastvalue2,$newlastvalue3,$newinnerloop1,$newinnerloop2,$newinnerloop3,$subscriptionid);
+ }
+}
+
+=head2 ModSubscription
+
+=over 4
+
+this function modify a subscription. Put all new values on input args.
+
+=back
+
+=cut
+sub ModSubscription {
+ my ($auser,$aqbooksellerid,$cost,$aqbudgetid,$startdate,
+ $periodicity,$dow,$numberlength,$weeklength,$monthlength,
+ $add1,$every1,$whenmorethan1,$setto1,$lastvalue1,$innerloop1,
+ $add2,$every2,$whenmorethan2,$setto2,$lastvalue2,$innerloop2,
+ $add3,$every3,$whenmorethan3,$setto3,$lastvalue3,$innerloop3,
+ $numberingmethod, $status, $biblionumber, $notes, $letter, $subscriptionid,$irregularity,$hemisphere,$callnumber,$numberpattern,$publisheddate)= @_;
+ my $dbh = C4::Context->dbh;
+ my $query = qq|
+ UPDATE subscription
+ SET librarian=?, aqbooksellerid=?,cost=?,aqbudgetid=?,startdate=?,
+ periodicity=?,dow=?,numberlength=?,weeklength=?,monthlength=?,
+ add1=?,every1=?,whenmorethan1=?,setto1=?,lastvalue1=?,innerloop1=?,
+ add2=?,every2=?,whenmorethan2=?,setto2=?,lastvalue2=?,innerloop2=?,
+ add3=?,every3=?,whenmorethan3=?,setto3=?,lastvalue3=?,innerloop3=?,
+ numberingmethod=?, status=?, biblionumber=?, notes=?, letter=?,irregularity=?,hemisphere=?,callnumber=?,numberpattern=? ,publisheddate=?
+ WHERE subscriptionid = ?
+ |;
+ my $sth=$dbh->prepare($query);
+ $sth->execute($auser,$aqbooksellerid,$cost,$aqbudgetid,$startdate,
+ $periodicity,$dow,$numberlength,$weeklength,$monthlength,
+ $add1,$every1,$whenmorethan1,$setto1,$lastvalue1,$innerloop1,
+ $add2,$every2,$whenmorethan2,$setto2,$lastvalue2,$innerloop2,
+ $add3,$every3,$whenmorethan3,$setto3,$lastvalue3,$innerloop3,
+ $numberingmethod, $status, $biblionumber, $notes, $letter, $irregularity,$hemisphere,$callnumber,$numberpattern,$publisheddate,$subscriptionid);
+ $sth->finish;
+}
+
+
+=head2 NewSubscription
+
+=over 4
+
+$subscriptionid = &NewSubscription($auser,$aqbooksellerid,$cost,$aqbudgetid,$biblionumber,
+ $startdate,$periodicity,$dow,$numberlength,$weeklength,$monthlength,
+ $add1,$every1,$whenmorethan1,$setto1,$lastvalue1,$innerloop1,
+ $add2,$every2,$whenmorethan2,$setto2,$lastvalue2,$innerloop2,
+ $add3,$every3,$whenmorethan3,$setto3,$lastvalue3,$innerloop3,
+ $numberingmethod, $status, $notes)
+
+Create a new subscription with value given on input args.
+
+return :
+the id of this new subscription
+
+=back
+
+=cut
+sub NewSubscription {
+ my ($auser,$aqbooksellerid,$cost,$aqbudgetid,$biblionumber,
+ $startdate,$periodicity,$dow,$numberlength,$weeklength,$monthlength,
+ $add1,$every1,$whenmorethan1,$setto1,$lastvalue1,
+ $add2,$every2,$whenmorethan2,$setto2,$lastvalue2,
+ $add3,$every3,$whenmorethan3,$setto3,$lastvalue3,
+ $numberingmethod, $status, $notes, $letter,$irregularity,$hemisphere,$callnumber,$numberpattern,$publisheddate) = @_;
+
+ my $dbh = C4::Context->dbh;
+#save subscription (insert into database)
+ my $query = qq|
+ INSERT INTO subscription
+ (librarian,aqbooksellerid,cost,aqbudgetid,biblionumber,
+ startdate,periodicity,dow,numberlength,weeklength,monthlength,
+ add1,every1,whenmorethan1,setto1,lastvalue1,
+ add2,every2,whenmorethan2,setto2,lastvalue2,
+ add3,every3,whenmorethan3,setto3,lastvalue3,
+ numberingmethod, status, notes, letter,irregularity,hemisphere,callnumber,numberpattern,publisheddate)
+ VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
+ |;
+ my $sth=$dbh->prepare($query);
+ $sth->execute(
+ $auser,$aqbooksellerid,$cost,$aqbudgetid,$biblionumber,
+ format_date_in_iso($startdate),$periodicity,$dow,$numberlength,$weeklength,$monthlength,
+ $add1,$every1,$whenmorethan1,$setto1,$lastvalue1,
+ $add2,$every2,$whenmorethan2,$setto2,$lastvalue2,
+ $add3,$every3,$whenmorethan3,$setto3,$lastvalue3,
+ $numberingmethod, $status, $notes, $letter,$irregularity,$hemisphere,$callnumber,$numberpattern,format_date_in_iso($publisheddate));
+
+
+#then create the 1st waited number
+ my $subscriptionid = $dbh->{'mysql_insertid'};
+ my $enddate = GetSubscriptionExpirationDate($subscriptionid);
+ my $query = qq(
+ INSERT INTO subscriptionhistory
+ (biblionumber, subscriptionid, histstartdate, enddate, missinglist, receivedlist, opacnote, librariannote)
+ VALUES (?,?,?,?,?,?,?,?)
+ );
+ $sth = $dbh->prepare($query);
+ $sth->execute($biblionumber, $subscriptionid, format_date_in_iso($startdate), format_date_in_iso($enddate), "", "", "", $notes);
+## User may have subscriptionid stored in MARC so check and fill it
+my $record=XMLgetbiblio($dbh,$biblionumber);
+$record=XML_xml2hash_onerecord($record);
+XML_writeline( $record, "subscriptionid", $subscriptionid,"biblios" );
+my $frameworkcode=MARCfind_frameworkcode($dbh,$biblionumber);
+NEWmodbiblio($dbh,$biblionumber,$record,$frameworkcode);
+# reread subscription to get a hash (for calculation of the 1st issue number)
+ my $query = qq(
+ SELECT *
+ FROM subscription
+ WHERE subscriptionid = ?
+ );
+ $sth = $dbh->prepare($query);
+ $sth->execute($subscriptionid);
+ my $val = $sth->fetchrow_hashref;
+
+# calculate issue number
+ my $serialseq = GetSeq($val);
+ my $query = qq|
+ INSERT INTO serial
+ (serialseq,subscriptionid,biblionumber,status, planneddate,publisheddate)
+ VALUES (?,?,?,?,?,?)
+ |;
+
+ $sth = $dbh->prepare($query);
+ $sth->execute($serialseq, $subscriptionid, $val->{'biblionumber'}, 1, format_date_in_iso($startdate),format_date_in_iso($publisheddate));
+ return $subscriptionid;
+}
+
+
+=head2 ReNewSubscription
+
+=over 4
+
+ReNewSubscription($subscriptionid,$user,$startdate,$numberlength,$weeklength,$monthlength,$note)
+
+this function renew a subscription with values given on input args.
+
+=back
+
+=cut
+sub ReNewSubscription {
+ my ($subscriptionid,$user,$startdate,$numberlength,$weeklength,$monthlength,$note) = @_;
+ my $dbh = C4::Context->dbh;
+ my $subscription = GetSubscription($subscriptionid);
+ my $record=XMLgetbiblio($dbh,$subscription->{biblionumber});
+ $record=XML_xml2hash_onerecord($record);
+ my $biblio = XMLmarc2koha_onerecord($dbh,$record,"biblios");
+ NewSuggestion($user,$subscription->{bibliotitle},$biblio->{author},$biblio->{publishercode},$biblio->{note},'','','','','',$subscription->{biblionumber});
+ # renew subscription
+ my $query = qq|
+ UPDATE subscription
+ SET startdate=?,numberlength=?,weeklength=?,monthlength=?
+ WHERE subscriptionid=?
+ |;
+my $sth=$dbh->prepare($query);
+ $sth->execute(format_date_in_iso($startdate),$numberlength,$weeklength,$monthlength, $subscriptionid);
+}
+
+
+=head2 NewIssue
+
+=over 4
+
+NewIssue($serialseq,$subscriptionid,$biblionumber,$status, $publisheddate, $planneddate)
+
+Create a new issue stored on the database.
+Note : we have to update the receivedlist and missinglist on subscriptionhistory for this subscription.
+
+=back
+
+=cut
+sub NewIssue {
+ my ($serialseq,$subscriptionid,$biblionumber,$status, $publisheddate, $planneddate,$itemnumber) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = qq|
+ INSERT INTO serial
+ (serialseq,subscriptionid,biblionumber,status,publisheddate,planneddate,itemnumber)
+ VALUES (?,?,?,?,?,?,?)
+ |;
+ my $sth = $dbh->prepare($query);
+ $sth->execute($serialseq,$subscriptionid,$biblionumber,$status,format_date_in_iso($publisheddate), format_date_in_iso($planneddate),$itemnumber);
+
+ my $query = qq|
+ SELECT missinglist,receivedlist
+ FROM subscriptionhistory
+ WHERE subscriptionid=?
+ |;
+ $sth = $dbh->prepare($query);
+ $sth->execute($subscriptionid);
+ my ($missinglist,$receivedlist) = $sth->fetchrow;
+ if ($status eq 2) {
+ $receivedlist .= ",$serialseq";
+ }
+ if ($status eq 4) {
+ $missinglist .= ",$serialseq";
+ }
+ my $query = qq|
+ UPDATE subscriptionhistory
+ SET receivedlist=?, missinglist=?
+ WHERE subscriptionid=?
+ |;
+ $sth=$dbh->prepare($query);
+ $sth->execute($receivedlist,$missinglist,$subscriptionid);
+}
+
+=head2 serialchangestatus
+
+=over 4
+
+serialchangestatus($serialid,$serialseq,$planneddate,$status,$notes)
+
+Change the status of a serial issue.
+Note: this was the older subroutine
+
+=back
+
+=cut
+sub serialchangestatus {
+ my ($serialid,$serialseq,$planneddate,$status,$notes)=@_;
+ # 1st, get previous status : if we change from "waited" to something else, then we will have to create a new "waited" entry
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("select subscriptionid,status from serial where serialid=?");
+ $sth->execute($serialid);
+ my ($subscriptionid,$oldstatus) = $sth->fetchrow;
+ # change status & update subscriptionhistory
+ if ($status eq 6){
+ delissue($serialseq, $subscriptionid)
+ }else{
+ $sth = $dbh->prepare("update serial set serialseq=?,planneddate=?,status=?,notes=? where serialid = ?");
+ $sth->execute($serialseq,format_date_in_iso($planneddate),$status,$notes,$serialid);
+
+ $sth = $dbh->prepare("select missinglist,receivedlist from subscriptionhistory where subscriptionid=?");
+ $sth->execute($subscriptionid);
+ my ($missinglist,$receivedlist) = $sth->fetchrow;
+ if ($status eq 2) {
+ $receivedlist .= "| $serialseq";
+ $receivedlist =~ s/^\| //g;
+ }
+ $missinglist .= "| $serialseq" if ($status eq 4) ;
+ $missinglist .= "| not issued $serialseq" if ($status eq 5);
+ $missinglist =~ s/^\| //g;
+ $sth=$dbh->prepare("update subscriptionhistory set receivedlist=?, missinglist=? where subscriptionid=?");
+ $sth->execute($receivedlist,$missinglist,$subscriptionid);
+ }
+ # create new waited entry if needed (ie : was a "waited" and has changed)
+ if ($oldstatus eq 1 && $status ne 1) {
+ $sth = $dbh->prepare("select * from subscription where subscriptionid = ? ");
+ $sth->execute($subscriptionid);
+ my $val = $sth->fetchrow_hashref;
+ # next issue number
+ my ($newserialseq,$newlastvalue1,$newlastvalue2,$newlastvalue3) = New_Get_Next_Seq($val);
+ my $nextplanneddate = GetNextDate($planneddate,$val);
+ NewIssue($newserialseq, $subscriptionid, $val->{'biblionumber'}, 1, $nextplanneddate);
+ $sth = $dbh->prepare("update subscription set lastvalue1=?, lastvalue2=?,lastvalue3=? where subscriptionid = ?");
+ $sth->execute($newlastvalue1,$newlastvalue2,$newlastvalue3,$subscriptionid);
+ }
+ # check if an alert must be sent... (= a letter is defined & status became "arrived"
+ $sth = $dbh->prepare("select * from subscription where subscriptionid = ? ");
+ $sth->execute($subscriptionid);
+ my $subscription = $sth->fetchrow_hashref;
+ if ($subscription->{letter} && $status eq 2) {
+ sendalerts('issue',$subscription->{subscriptionid},$subscription->{letter});
+ }
+}
+
+
+
+
+=head2 HasSubscriptionExpired
+
+=over 4
+
+1 or 0 = HasSubscriptionExpired($subscriptionid)
+
+the subscription has expired when the next issue to arrive is out of subscription limit.
+
+return :
+1 if true, 0 if false.
+
+=back
+
+=cut
+sub HasSubscriptionExpired {
+ my ($subscriptionid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $subscription = GetSubscription($subscriptionid);
+ # we don't do the same test if the subscription is based on X numbers or on X weeks/months
+ if ($subscription->{numberlength} ) {
+ my $query = qq|
+ SELECT count(*)
+ FROM serial
+ WHERE subscriptionid=? AND planneddate>=?
+ |;
+ my $sth = $dbh->prepare($query);
+ $sth->execute($subscriptionid,$subscription->{startdate});
+ my $res = $sth->fetchrow;
+ if ($subscription->{numberlength}>=$res) {
+ return 0;
+ } else {
+ return 1;
+ }
+ } else {
+ #a little bit more tricky if based on X weeks/months : search if the latest issue waited is not after subscription startdate + duration
+ my $query = qq|
+ SELECT max(planneddate)
+ FROM serial
+ WHERE subscriptionid=?
+ |;
+ my $sth = $dbh->prepare($query);
+ $sth->execute($subscriptionid);
+ my $res = $sth->fetchrow;
+ my $endofsubscriptiondate;
+ my $duration;
+ $duration=get_duration($subscription->{monthlength}." months") if ($subscription->{monthlength});
+ $duration=get_duration($subscription->{weeklength}." weeks") if ($subscription->{weeklength});
+
+ $endofsubscriptiondate = DATE_Add_Duration($subscription->{startdate},$duration) ;
+ return 1 if ($res ge $endofsubscriptiondate);
+ return 0;
+ }
+}
+
+=head2 SetDistributedto
+
+=over 4
+
+SetDistributedto($distributedto,$subscriptionid);
+This function update the value of distributedto for a subscription given on input arg.
+
+=back
+
+=cut
+sub SetDistributedto {
+ my ($distributedto,$subscriptionid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = qq|
+ UPDATE subscription
+ SET distributedto=?
+ WHERE subscriptionid=?
+ |;
+ my $sth = $dbh->prepare($query);
+ $sth->execute($distributedto,$subscriptionid);
+}
+
+=head2 DelSubscription
+
+=over 4
+
+DelSubscription($subscriptionid)
+this function delete the subscription which has $subscriptionid as id.
+
+=back
+
+=cut
+sub DelSubscription {
+ my ($subscriptionid,$biblionumber) = @_;
+ my $dbh = C4::Context->dbh;
+## User may have subscriptionid stored in MARC so check and remove it
+my $record=XMLgetbibliohash($dbh,$biblionumber);
+XML_writeline( $record, "subscriptionid", "","biblios" );
+my $frameworkcode=MARCfind_frameworkcode($dbh,$biblionumber);
+NEWmodbiblio($dbh,$biblionumber,$record,$frameworkcode);
+ $subscriptionid=$dbh->quote($subscriptionid);
+ $dbh->do("DELETE FROM subscription WHERE subscriptionid=$subscriptionid");
+ $dbh->do("DELETE FROM subscriptionhistory WHERE subscriptionid=$subscriptionid");
+ $dbh->do("DELETE FROM serial WHERE subscriptionid=$subscriptionid");
+
+}
+
+=head2 DelIssue
+
+=over 4
+
+DelIssue($serialseq,$subscriptionid)
+this function delete an issue which has $serialseq and $subscriptionid given on input arg.
+
+=back
+
+=cut
+sub DelIssue {
+ my ($serialseq,$subscriptionid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = qq|
+ DELETE FROM serial
+ WHERE serialseq= ?
+ AND subscriptionid= ?
+ |;
+ my $sth = $dbh->prepare($query);
+ $sth->execute($serialseq,$subscriptionid);
+}
+
+=head2 GetMissingIssues
+
+=over 4
+
+($count, at issuelist) = &GetMissingIssues($supplierid,$serialid)
+
+this function select missing issues on database - where serial.status = 4
+
+return :
+a count of the number of missing issues
+the issuelist into a table. Each line of this table containts a ref to a hash which it containts
+name,title,planneddate,serialseq,serial.subscriptionid from tables : subscription, serial & biblio
+
+=back
+
+=cut
+sub GetMissingIssues {
+ my ($supplierid,$serialid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth;
+ my $byserial='';
+ if($serialid) {
+ $byserial = "and serialid = ".$serialid;
+ }
+ if ($supplierid) {
+ $sth = $dbh->prepare("SELECT serialid,aqbooksellerid,name,title,planneddate,serialseq,serial.subscriptionid,claimdate
+ FROM subscription, serial, biblio
+ LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
+ WHERE subscription.subscriptionid = serial.subscriptionid AND
+ serial.STATUS = 4 and
+ subscription.aqbooksellerid=$supplierid and
+ biblio.biblionumber = subscription.biblionumber ".$byserial." order by title
+ ");
+ } else {
+ $sth = $dbh->prepare("SELECT serialid,aqbooksellerid,name,title,planneddate,serialseq,serial.subscriptionid,claimdate
+ FROM subscription, serial, biblio
+ LEFT JOIN aqbooksellers ON subscription.aqbooksellerid = aqbooksellers.id
+ WHERE subscription.subscriptionid = serial.subscriptionid AND
+ serial.STATUS =4 and
+ biblio.biblionumber = subscription.biblionumber ".$byserial." order by title
+ ");
+ }
+ $sth->execute;
+ my @issuelist;
+ my $last_title;
+ my $odd=0;
+ my $count=0;
+ while (my $line = $sth->fetchrow_hashref) {
+ $odd++ unless $line->{title} eq $last_title;
+ $last_title = $line->{title} if ($line->{title});
+ $line->{planneddate} = format_date($line->{planneddate});
+ $line->{claimdate} = format_date($line->{claimdate});
+ $line->{'odd'} = 1 if $odd %2 ;
+ $count++;
+ push @issuelist,$line;
+ }
+ return $count, at issuelist;
+}
+
+=head2 removeMissingIssue
+
+=over 4
+
+removeMissingIssue($subscriptionid)
+
+this function removes an issue from being part of the missing string in
+subscriptionlist.missinglist column
+
+called when a missing issue is found from the statecollection.pl file
+
+=back
+
+=cut
+sub removeMissingIssue {
+ my ($sequence,$subscriptionid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("SELECT * FROM subscriptionhistory WHERE subscriptionid = ?");
+ $sth->execute($subscriptionid);
+ my $data = $sth->fetchrow_hashref;
+ my $missinglist = $data->{'missinglist'};
+ my $missinglistbefore = $missinglist;
+ # warn $missinglist." before";
+ $missinglist =~ s/($sequence)//;
+ # warn $missinglist." after";
+ if($missinglist ne $missinglistbefore){
+ $missinglist =~ s/\|\s\|/\|/g;
+ $missinglist =~ s/^\| //g;
+ $missinglist =~ s/\|$//g;
+ my $sth2= $dbh->prepare("UPDATE subscriptionhistory
+ SET missinglist = ?
+ WHERE subscriptionid = ?");
+ $sth2->execute($missinglist,$subscriptionid);
+ }
+}
+
+=head2 updateClaim
+
+=over 4
+
+&updateClaim($serialid)
+
+this function updates the time when a claim is issued for late/missing items
+
+called from claims.pl file
+
+=back
+
+=cut
+sub updateClaim {
+ my ($serialid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("UPDATE serial SET claimdate = now()
+ WHERE serialid = ?
+ ");
+ $sth->execute($serialid);
+}
+
+=head2 getsupplierbyserialid
+
+=over 4
+
+($result) = &getsupplierbyserialid($serialid)
+
+this function is used to find the supplier id given a serial id
+
+return :
+hashref containing serialid, subscriptionid, and aqbooksellerid
+
+=back
+
+=cut
+sub getsupplierbyserialid {
+ my ($serialid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("SELECT serialid, serial.subscriptionid, aqbooksellerid
+ FROM serial, subscription
+ WHERE serial.subscriptionid = subscription.subscriptionid
+ AND serialid = ?
+ ");
+ $sth->execute($serialid);
+ my $line = $sth->fetchrow_hashref;
+ my $result = $line->{'aqbooksellerid'};
+ return $result;
+}
+
+=head2 check_routing
+
+=over 4
+
+($result) = &check_routing($subscriptionid)
+
+this function checks to see if a serial has a routing list and returns the count of routingid
+used to show either an 'add' or 'edit' link
+=back
+
+=cut
+sub check_routing {
+ my ($subscriptionid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("SELECT count(routingid) routingids FROM subscriptionroutinglist, subscription
+ WHERE subscription.subscriptionid = subscriptionroutinglist.subscriptionid
+ AND subscription.subscriptionid = ? ORDER BY ranking ASC
+ ");
+ $sth->execute($subscriptionid);
+ my $line = $sth->fetchrow_hashref;
+ my $result = $line->{'routingids'};
+ return $result;
+}
+
+=head2 addroutingmember
+
+=over 4
+
+&addroutingmember($bornum,$subscriptionid)
+
+this function takes a borrowernumber and subscriptionid and add the member to the
+routing list for that serial subscription and gives them a rank on the list
+of either 1 or highest current rank + 1
+
+=back
+
+=cut
+sub addroutingmember {
+ my ($bornum,$subscriptionid) = @_;
+ my $rank;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("SELECT max(ranking) rank FROM subscriptionroutinglist WHERE subscriptionid = ?");
+ $sth->execute($subscriptionid);
+ while(my $line = $sth->fetchrow_hashref){
+ if($line->{'rank'}>0){
+ $rank = $line->{'rank'}+1;
+ } else {
+ $rank = 1;
+ }
+ }
+ $sth = $dbh->prepare("INSERT INTO subscriptionroutinglist VALUES (null,?,?,?,null)");
+ $sth->execute($subscriptionid,$bornum,$rank);
+}
+
+=head2 reorder_members
+
+=over 4
+
+&reorder_members($subscriptionid,$routingid,$rank)
+
+this function is used to reorder the routing list
+
+it takes the routingid of the member one wants to re-rank and the rank it is to move to
+- it gets all members on list puts their routingid's into an array
+- removes the one in the array that is $routingid
+- then reinjects $routingid at point indicated by $rank
+- then update the database with the routingids in the new order
+
+=back
+
+=cut
+sub reorder_members {
+ my ($subscriptionid,$routingid,$rank) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("SELECT * FROM subscriptionroutinglist WHERE subscriptionid = ? ORDER BY ranking ASC");
+ $sth->execute($subscriptionid);
+ my @result;
+ while(my $line = $sth->fetchrow_hashref){
+ push(@result,$line->{'routingid'});
+ }
+ # To find the matching index
+ my $i;
+ my $key = -1; # to allow for 0 being a valid response
+ for ($i = 0; $i < @result; $i++) {
+ if ($routingid == $result[$i]) {
+ $key = $i; # save the index
+ last;
+ }
+ }
+ # if index exists in array then move it to new position
+ if($key > -1 && $rank > 0){
+ my $new_rank = $rank-1; # $new_rank is what you want the new index to be in the array
+ my $moving_item = splice(@result, $key, 1);
+ splice(@result, $new_rank, 0, $moving_item);
+ }
+ for(my $j = 0; $j < @result; $j++){
+ my $sth = $dbh->prepare("UPDATE subscriptionroutinglist SET ranking = '" . ($j+1) . "' WHERE routingid = '". $result[$j]."'");
+ $sth->execute;
+ }
+}
+
+=head2 delroutingmember
+
+=over 4
+
+&delroutingmember($routingid,$subscriptionid)
+
+this function either deletes one member from routing list if $routingid exists otherwise
+deletes all members from the routing list
+
+=back
+
+=cut
+sub delroutingmember {
+ # if $routingid exists then deletes that row otherwise deletes all with $subscriptionid
+ my ($routingid,$subscriptionid) = @_;
+ my $dbh = C4::Context->dbh;
+ if($routingid){
+ my $sth = $dbh->prepare("DELETE FROM subscriptionroutinglist WHERE routingid = ?");
+ $sth->execute($routingid);
+ reorder_members($subscriptionid,$routingid);
+ } else {
+ my $sth = $dbh->prepare("DELETE FROM subscriptionroutinglist WHERE subscriptionid = ?");
+ $sth->execute($subscriptionid);
+ }
+}
+
+=head2 getroutinglist
+
+=over 4
+
+($count, at routinglist) = &getroutinglist($subscriptionid)
+
+this gets the info from the subscriptionroutinglist for $subscriptionid
+
+return :
+a count of the number of members on routinglist
+the routinglist into a table. Each line of this table containts a ref to a hash which containts
+routingid - a unique id, borrowernumber, ranking, and biblionumber of subscription
+
+=back
+
+=cut
+sub getroutinglist {
+ my ($subscriptionid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("SELECT routingid, borrowernumber,
+ ranking, biblionumber FROM subscriptionroutinglist, subscription
+ WHERE subscription.subscriptionid = subscriptionroutinglist.subscriptionid
+ AND subscription.subscriptionid = ? ORDER BY ranking ASC
+ ");
+ $sth->execute($subscriptionid);
+ my @routinglist;
+ my $count=0;
+ while (my $line = $sth->fetchrow_hashref) {
+ $count++;
+ push(@routinglist,$line);
+ }
+ return ($count, at routinglist);
+}
+
+=head2 abouttoexpire
+
+=over 4
+
+$result = &abouttoexpire($subscriptionid)
+
+this function alerts you to the penultimate issue for a serial subscription
+
+returns 1 - if this is the penultimate issue
+returns 0 - if not
+
+=back
+
+=cut
+
+sub abouttoexpire {
+ my ($subscriptionid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $subscription = GetSubscription($subscriptionid);
+ # we don't do the same test if the subscription is based on X numbers or on X weeks/months
+ if ($subscription->{numberlength}) {
+ my $sth = $dbh->prepare("select count(*) from serial where subscriptionid=? and planneddate>=?");
+ $sth->execute($subscriptionid,$subscription->{startdate});
+ my $res = $sth->fetchrow;
+ # warn "length: ".$subscription->{numberlength}." vs count: ".$res;
+ if ($subscription->{numberlength}==$res) {
+ return 1;
+ } else {
+ return 0;
+ }
+ } else {
+ # a little bit more tricky if based on X weeks/months : search if the latest issue waited is not after subscription startdate + duration
+ my $sth = $dbh->prepare("select max(planneddate) from serial where subscriptionid=?");
+ $sth->execute($subscriptionid);
+ my $res = $sth->fetchrow;
+ my $endofsubscriptiondate;
+my $duration;
+ $duration=get_duration($subscription->{monthlength}." months") if ($subscription->{monthlength});
+ $duration=get_duration($subscription->{weeklength}." weeks") if ($subscription->{weeklength});
+
+ $endofsubscriptiondate = DATE_Add_Duration($subscription->{startdate},$duration) ;
+ my $per = $subscription->{'periodicity'};
+ my $x = 0;
+ if ($per == 1) { $x = '1 days'; }
+ if ($per == 2) { $x = '1 weeks'; }
+ if ($per == 3) { $x = '2 weeks'; }
+ if ($per == 4) { $x = '3 weeks'; }
+ if ($per == 5) { $x = '1 months'; }
+ if ($per == 6) { $x = '2 months'; }
+ if ($per == 7 || $per == 8) { $x = '3 months'; }
+ if ($per == 9) { $x = '6 months'; }
+ if ($per == 10) { $x = '1 years'; }
+ if ($per == 11) { $x = '2 years'; }
+ my $duration=get_duration("-".$x) ;
+ my $datebeforeend = DATE_Add_Duration($endofsubscriptiondate,$duration); # if ($subscription->{weeklength});
+ # warn "DATE BEFORE END: $datebeforeend";
+ return 1 if ($res >= $datebeforeend && $res < $endofsubscriptiondate);
+ return 0;
+ }
+}
+
+
+
+=head2 GetNextDate
+
+=over 4
+
+($resultdate) = &GetNextDate($planneddate,$subscription)
+
+this function takes the planneddate and will return the next issue's date and will skip dates if there
+exists an irregularity
+- eg if periodicity is monthly and $planneddate is 2007-02-10 but if March and April is to be
+skipped then the returned date will be 2007-05-10
+
+return :
+$resultdate - then next date in the sequence
+
+=back
+
+=cut
+sub GetNextDate {
+ my ($planneddate,$subscription) = @_;
+ my @irreg = split(/\|/,$subscription->{irregularity});
+ my $dateobj=DATE_obj($planneddate);
+ my $dayofweek = $dateobj->day_of_week;
+ my $month=$dateobj->month;
+ my $resultdate;
+
+ if ($subscription->{periodicity} == 1) {
+ my %irreghash;
+ for(my $i=0;$i<@irreg;$i++){
+ $irreghash{$irreg[$i]}=1;
+ }
+my $duration=get_duration("1 days");
+ for(my $i=0;$i<@irreg;$i++){
+ if($dayofweek == 7){ $dayofweek = 0; }
+
+ if($irreghash{$dayofweek+1}){
+ $planneddate = DATE_Add_Duration($planneddate,$duration);
+ $dayofweek++;
+ }
+ }
+ $resultdate=DATE_Add_Duration($planneddate,$duration);
+ }
+ if ($subscription->{periodicity} == 2) {
+ my $wkno = $dateobj->week_number;
+my $duration=get_duration("1 weeks");
+ for(my $i = 0;$i < @irreg; $i++){
+ if($wkno > 52) { $wkno = 0; } # need to rollover at January
+ if($irreg[$i] == ($wkno+1)){
+ $planneddate = DATE_Add_Duration($planneddate,$duration);
+ $wkno++;
+ }
+ }
+ $resultdate=DATE_Add_Duration($planneddate,$duration);
+ }
+ if ($subscription->{periodicity} == 3) {
+ my $wkno = $dateobj->week_number;
+my $duration=get_duration("2 weeks");
+ for(my $i = 0;$i < @irreg; $i++){
+ if($wkno > 52) { $wkno = 0; } # need to rollover at January
+ if($irreg[$i] == ($wkno+1)){
+ $planneddate = DATE_Add_Duration($planneddate,$duration);
+ $wkno++;
+ }
+ }
+ $resultdate=DATE_Add_Duration($planneddate,$duration);
+ }
+ if ($subscription->{periodicity} == 4) {
+ my $wkno = $dateobj->week_number;
+my $duration=get_duration("3 weeks");
+ for(my $i = 0;$i < @irreg; $i++){
+ if($wkno > 52) { $wkno = 0; } # need to rollover at January
+ if($irreg[$i] == ($wkno+1)){
+ $planneddate = DATE_Add_Duration($planneddate,$duration);
+ $wkno++;
+ }
+ }
+ $resultdate=DATE_Add_Duration($planneddate,$duration);
+ }
+ if ($subscription->{periodicity} == 5) {
+my $duration=get_duration("1 months");
+ for(my $i = 0;$i < @irreg; $i++){
+ # warn $irreg[$i];
+ # warn $month;
+ if($month == 12) { $month = 0; } # need to rollover to check January
+ if($irreg[$i] == ($month+1)){ # check next one to see if is to be skipped
+ $planneddate = DATE_Add_Duration($planneddate,$duration);
+ $month++; # to check if following ones are to be skipped too
+ }
+ }
+ $resultdate=DATE_Add_Duration($planneddate,$duration);
+ }
+ if ($subscription->{periodicity} == 6) {
+my $duration=get_duration("2 months");
+ for(my $i = 0;$i < @irreg; $i++){
+ # warn $irreg[$i];
+ # warn $month;
+ if($month == 12) { $month = 0; } # need to rollover to check January
+ if($irreg[$i] == ($month+1)){ # check next one to see if is to be skipped
+ $planneddate = DATE_Add_Duration($planneddate,$duration);
+ $month++; # to check if following ones are to be skipped too
+ }
+ }
+ $resultdate=DATE_Add_Duration($planneddate,$duration);
+ }
+ if ($subscription->{periodicity} == 7 || $subscription->{periodicity} == 8 ) {
+my $duration=get_duration("3 months");
+ for(my $i = 0;$i < @irreg; $i++){
+ # warn $irreg[$i];
+ # warn $month;
+ if($month == 12) { $month = 0; } # need to rollover to check January
+ if($irreg[$i] == ($month+1)){ # check next one to see if is to be skipped
+ $planneddate = DATE_Add_Duration($planneddate,$duration);
+ $month++; # to check if following ones are to be skipped too
+ }
+ }
+ $resultdate=DATE_Add_Duration($planneddate,$duration);
+ }
+
+ if ($subscription->{periodicity} == 9) {
+my $duration=get_duration("6 months");
+ for(my $i = 0;$i < @irreg; $i++){
+ # warn $irreg[$i];
+ # warn $month;
+ if($month == 12) { $month = 0; } # need to rollover to check January
+ if($irreg[$i] == ($month+1)){ # check next one to see if is to be skipped
+ $planneddate = DATE_Add_Duration($planneddate,$duration);
+ $month++; # to check if following ones are to be skipped too
+ }
+ }
+ $resultdate=DATE_Add_Duration($planneddate,$duration);
+ }
+ if ($subscription->{periodicity} == 10) {
+my $duration=get_duration("1 years");
+ $resultdate=DATE_Add_Duration($planneddate,$duration);
+ }
+ if ($subscription->{periodicity} == 11) {
+ my $duration=get_duration("2 years");
+ $resultdate=DATE_Add_Duration($planneddate,$duration);
+ }
+ # warn "date: ".$resultdate;
+ return $resultdate;
+}
+
+
+
+1;
+__END__
Index: Stats.pm
===================================================================
RCS file: Stats.pm
diff -N Stats.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Stats.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,245 @@
+package C4::Stats;
+
+# $Id: Stats.pm,v 1.1.2.1 2007/03/10 01:35:34 tgarip1957 Exp $
+# Modified by TG
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+require Exporter;
+
+use C4::Context;
+use vars qw($VERSION @ISA @EXPORT);
+
+# set the version for version checking
+$VERSION = 0.01;
+
+=head1 NAME
+
+C4::Stats - Update Koha statistics (log)
+
+=head1 SYNOPSIS
+
+ use C4::Stats;
+
+=head1 DESCRIPTION
+
+The C<&UpdateStats> function adds an entry to the statistics table in
+the Koha database, which acts as an activity log.
+
+=head1 FUNCTIONS
+
+=over 2
+
+=cut
+
+ at ISA = qw(Exporter);
+ at EXPORT = qw(&UpdateStats &statsreport &TotalOwing
+&TotalPaid &getcharges &Getpaidbranch &unfilledreserves &getcredits &getinvoices);
+
+=item UpdateStats
+
+ &UpdateStats($env, $branch, $type, $value, $other, $itemnumber,
+ $itemtype, $borrowernumber);
+
+Adds a line to the statistics table of the Koha database. In effect,
+it logs an event.
+
+C<$branch>, C<$type>, C<$value>, C<$other>, C<$itemnumber>,
+C<$itemtype>, and C<$borrowernumber> correspond to the fields of the
+statistics table in the Koha database.
+
+If C<$branch> is the empty string, the branch code will be taken from
+C<$env-E<gt>{branchcode}>.
+
+C<$env-E<gt>{usercode}> specifies the value of the C<usercode> field.
+
+=cut
+#'
+sub UpdateStats {
+ #module to insert stats data into stats table
+ my ($env,$branch,$type,$amount,$other,$itemnum,$itemtype,$borrowernumber,$accountno)=@_;
+ my $dbh = C4::Context->dbh;
+ $env=C4::Context->userenv unless $env;
+ if ($branch eq ''){
+ $branch=$env->{'branchcode'};
+ }
+ my $user = C4::Context->userenv;
+# print $borrowernumber;
+ my $userid=$user->{'cardnumber'} if $user;
+ # FIXME - Use $dbh->do() instead
+ my $sth=$dbh->prepare("Insert into statistics (datetime,branch,type,usercode,value,
+ other,itemnumber,itemtype,borrowernumber,proccode) values (now(),?,?,?,?,?,?,?,?,?)");
+ $sth->execute($branch,$type,$userid,$amount,$other,$itemnum,$itemtype,$borrowernumber,$accountno);
+ $sth->finish;
+}
+
+# Otherwise, it'd need a POD.
+sub TotalPaid {
+ my ($time,$time2)=@_;
+ $time2=$time unless $time2;
+ my $dbh = C4::Context->dbh;
+
+
+ my $query="Select * from accountlines,borrowers where (accounttype = 'Pay' or accounttype='W')
+ and accountlines.borrowernumber = borrowers.borrowernumber";
+ my @bind = ();
+ if ($time eq 'today'){
+ $query .= " and date = now()";
+ } else {
+ $query.=" and date>=? and date<=?";
+ @bind = ($time,$time2);
+ }
+
+
+
+
+ $query.=" order by timestamp";
+
+ # print $query;
+
+ my $sth=$dbh->prepare($query);
+
+ # $sth->execute();
+ $sth->execute(@bind);
+ my @results;
+ my $i=0;
+ while (my $data=$sth->fetchrow_hashref){
+ $results[$i]=$data;
+ $i++;
+ }
+ $sth->finish;
+ # print $query;
+ return(@results);
+}
+
+# Otherwise, it needs a POD.
+sub getcharges{
+ my($borrowerno,$offset,$accountno)=@_;
+ my $dbh = C4::Context->dbh;
+ my $query="";
+ my $sth;
+
+ # getcharges is now taking accountno. as an argument
+ if ($offset){
+ $sth=$dbh->prepare("Select * from accountlines where borrowernumber=?
+ and accountno = ? and amount>0");
+ $sth->execute($borrowerno,$offset);
+
+ # this bit left in for old 2 arg usage of getcharges
+ } else {
+ $sth=$dbh->prepare("Select * from accountlines where borrowernumber=?
+ and accountno = ?");
+ $sth->execute($borrowerno,$accountno);
+ }
+
+ # print $query,"<br>";
+ my $i=0;
+ my @results;
+ while (my $data=$sth->fetchrow_hashref){
+ # if ($data->{'timestamp'} == $timestamp){
+ $results[$i]=$data;
+ $i++;
+ # }
+ }
+ return(@results);
+}
+
+# Otherwise, it needs a POD.
+sub getcredits{
+ my ($date,$date2)=@_;
+ my $dbh = C4::Context->dbh;
+
+
+
+ my $sth=$dbh->prepare("Select * from accountlines,borrowers where (( (accounttype <> 'Pay'))
+ and amount < 0 and accountlines.borrowernumber = borrowers.borrowernumber
+ and date >=? and date <=?)");
+ $sth->execute($date, $date2);
+
+ my $i=0;
+ my @results;
+ while (my $data=$sth->fetchrow_hashref){
+ $results[$i]=$data;
+ $i++;
+ }
+ return(@results);
+}
+
+sub getinvoices{
+ my ($date,$date2)=@_;
+ my $dbh = C4::Context->dbh;
+ my $sth=$dbh->prepare("Select * from accountlines,borrowers where amount>0 and amountoutstanding > 0 and accountlines.borrowernumber = borrowers.borrowernumber
+ and (date >=? and date <=?)");
+ $sth->execute($date, $date2);
+
+ my $i=0;
+ my @results;
+ while (my $data=$sth->fetchrow_hashref){
+ $results[$i]=$data;
+ $i++;
+ }
+ return(@results);
+}
+
+
+# Otherwise, this needs a POD.
+sub Getpaidbranch{
+ my($date,$borrno)=@_;
+ my $dbh = C4::Context->dbh;
+ my $sth=$dbh->prepare("select * from statistics where type='payment' and datetime >? and borrowernumber=?");
+ $sth->execute($date,$borrno);
+ # print $query;
+ my $data=$sth->fetchrow_hashref;
+ $sth->finish;
+ return($data->{'branch'});
+}
+
+# FIXME - This is only used in reservereport.pl and reservereport.xls,
+# neither of which is used.
+# Otherwise, it needs a POD.
+sub unfilledreserves {
+ my $dbh = C4::Context->dbh;
+
+ my $i=0;
+ my @results;
+
+ my $sth=$dbh->prepare("select *,biblio.title from reserves,biblio,borrowers where (found <> '1' or found is NULL) and cancellationdate
+ is NULL and biblio.biblionumber=reserves.biblionumber and
+ reserves.borrowernumber=borrowers.borrowernumber
+ order by
+ reserves.reservedate,biblio.title");
+ $sth->execute;
+ while (my $data=$sth->fetchrow_hashref){
+ $results[$i]=$data;
+ $i++;
+ }
+ $sth->finish;
+ return($i,\@results);
+}
+
+1;
+__END__
+
+=back
+
+=head1 AUTHOR
+
+Koha Developement team <info at koha.org>
+
+=cut
+
Index: Suggestions.pm
===================================================================
RCS file: Suggestions.pm
diff -N Suggestions.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Suggestions.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,466 @@
+package C4::Suggestions;
+
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+# $Id: Suggestions.pm,v 1.1.2.1 2007/03/10 01:35:34 tgarip1957 Exp $
+
+use strict;
+require Exporter;
+use C4::Context;
+use C4::Output;
+use Mail::Sendmail;
+use vars qw($VERSION @ISA @EXPORT);
+
+# set the version for version checking
+$VERSION = do { my @v = '$Revision: 1.1.2.1 $' =~ /\d+/g;
+ shift(@v) . "." . join("_", map {sprintf "%03d", $_ } @v); };
+
+=head1 NAME
+
+C4::Suggestions - Some useful functions for dealings with suggestions.
+
+=head1 SYNOPSIS
+
+use C4::Suggestions;
+
+=head1 DESCRIPTION
+
+=over 4
+
+The functions in this module deal with the suggestions in OPAC and in librarian interface
+
+A suggestion is done in the OPAC. It has the status "ASKED"
+
+When a librarian manages the suggestion, he can set the status to "REJECTED" or "ACCEPTED".
+
+When the book is ordered, the suggestion status becomes "ORDERED"
+
+When a book is ordered and arrived in the library, the status becomes "AVAILABLE"
+
+All suggestions of a borrower can be seen by the borrower itself.
+Suggestions done by other borrowers can be seen when not "AVAILABLE"
+
+=back
+
+=head1 FUNCTIONS
+
+=cut
+
+ at ISA = qw(Exporter);
+ at EXPORT = qw(
+ &NewSuggestion
+ &SearchSuggestion
+ &GetSuggestion
+ &DelSuggestion
+ &CountSuggestion
+ &ModStatus
+ &ConnectSuggestionAndBiblio
+ &GetSuggestionFromBiblionumber
+ );
+
+=head2 SearchSuggestion
+
+=over 4
+
+(\@array) = &SearchSuggestion($user,$author,$title,$publishercode,$status,$suggestedbyme)
+
+searches for a suggestion
+
+return :
+C<\@array> : the suggestions found. Array of hash.
+Note the status is stored twice :
+* in the status field
+* as parameter ( for example ASKED => 1, or REJECTED => 1) . This is for template & translation purposes.
+
+=back
+
+=cut
+
+sub SearchSuggestion {
+ my ($user,$author,$title,$publishercode,$status,$suggestedbyme)=@_;
+ my $dbh = C4::Context->dbh;
+ my $query = qq|
+ SELECT suggestions.*,
+ U1.surname AS surnamesuggestedby,
+ U1.firstname AS firstnamesuggestedby,
+ U2.surname AS surnamemanagedby,
+ U2.firstname AS firstnamemanagedby
+ FROM suggestions
+ LEFT JOIN borrowers AS U1 ON suggestedby=U1.borrowernumber
+ LEFT JOIN borrowers AS U2 ON managedby=U2.borrowernumber
+ WHERE 1=1 |;
+
+ my @sql_params;
+ if ($author) {
+ push @sql_params,"%".$author."%";
+ $query .= " and author like ?";
+ }
+ if ($title) {
+ push @sql_params,"%".$title."%";
+ $query .= " and suggestions.title like ?";
+ }
+ if ($publishercode) {
+ push @sql_params,"%".$publishercode."%";
+ $query .= " and publishercode like ?";
+ }
+ if ($status) {
+ push @sql_params,$status;
+ $query .= " and status=?";
+ }
+
+ if (C4::Context->preference("IndependantBranches")) {
+ my $userenv = C4::Context->userenv;
+ if ($userenv) {
+ unless ($userenv->{flags} == 1){
+ push @sql_params,$userenv->{branch};
+ $query .= " and (U1.branchcode = ? or U1.branchcode ='')";
+ }
+ }
+ }
+ if ($suggestedbyme) {
+ unless ($suggestedbyme eq -1) {
+ push @sql_params,$user;
+ $query .= " and suggestedby=?";
+ }
+ } else {
+ $query .= " and managedby is NULL";
+ }
+ my $sth=$dbh->prepare($query);
+ $sth->execute(@sql_params);
+ my @results;
+ my $even=1; # the even variable is used to set even / odd lines, for highlighting
+ while (my $data=$sth->fetchrow_hashref){
+ $data->{$data->{STATUS}} = 1;
+ if ($even) {
+ $even=0;
+ $data->{even}=1;
+ } else {
+ $even=1;
+ }
+ push(@results,$data);
+ }
+ return (\@results);
+}
+
+=head2 GetSuggestion
+
+=over 4
+
+\%sth = &GetSuggestion($suggestionid)
+
+this function get the detail of the suggestion $suggestionid (input arg)
+
+return :
+ the result of the SQL query as a hash : $sth->fetchrow_hashref.
+
+=back
+
+=cut
+sub GetSuggestion {
+ my ($suggestionid) = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = qq|
+ SELECT *
+ FROM suggestions
+ WHERE suggestionid=?
+ |;
+ my $sth = $dbh->prepare($query);
+ $sth->execute($suggestionid);
+ return($sth->fetchrow_hashref);
+}
+
+=head2 GetSuggestionFromBiblionumber
+
+=over 4
+
+$suggestionid = &GetSuggestionFromBiblionumber($dbh,$biblionumber)
+
+Get a suggestion from it's biblionumber.
+
+return :
+the id of the suggestion which is related to the biblionumber given on input args.
+
+=back
+
+=cut
+sub GetSuggestionFromBiblionumber {
+ my ($dbh,$biblionumber) = @_;
+ my $query = qq|
+ SELECT suggestionid
+ FROM suggestions
+ WHERE biblionumber=?
+ |;
+ my $sth = $dbh->prepare($query);
+ $sth->execute($biblionumber);
+ my ($suggestionid) = $sth->fetchrow;
+ return $suggestionid;
+}
+
+
+=head2 CountSuggestion
+
+=over 4
+
+&CountSuggestion($status)
+
+Count the number of suggestions with the status given on input argument.
+the arg status can be :
+
+=over
+
+=over
+
+=item * ASKED : asked by the user, not dealed by the librarian
+
+=item * ACCEPTED : accepted by the librarian, but not yet ordered
+
+=item * REJECTED : rejected by the librarian (definitive status)
+
+=item * ORDERED : ordered by the librarian (acquisition module)
+
+=back
+
+=back
+
+return :
+the number of suggestion with this status.
+
+=back
+
+=cut
+sub CountSuggestion {
+ my ($status) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth;
+ if (C4::Context->preference("IndependantBranches")){
+ my $userenv = C4::Context->userenv;
+ if ($userenv->{flags} == 1){
+ my $query = qq |
+ SELECT count(*)
+ FROM suggestions
+ WHERE status=?
+ |;
+ $sth = $dbh->prepare($query);
+ $sth->execute($status);
+ }
+ else {
+ my $query = qq |
+ SELECT count(*)
+ FROM suggestions,borrowers
+ WHERE status=?
+ AND borrowers.borrowernumber=suggestions.suggestedby
+ AND (borrowers.branchcode='' OR borrowers.branchcode =?)
+ |;
+ $sth = $dbh->prepare($query);
+ $sth->execute($status,$userenv->{branch});
+ }
+ }
+ else {
+ my $query = qq |
+ SELECT count(*)
+ FROM suggestions
+ WHERE status=?
+ |;
+ $sth = $dbh->prepare($query);
+ $sth->execute($status);
+ }
+ my ($result) = $sth->fetchrow;
+ return $result;
+}
+
+=head2 NewSuggestion
+
+
+=over 4
+
+&NewSuggestion($borrowernumber,$title,$author,$publishercode,$note,$copyrightdate,$volumedesc,$publicationyear,$place,$isbn,$biblionumber)
+
+Insert a new suggestion on database with value given on input arg.
+
+=back
+
+=cut
+sub NewSuggestion {
+ my ($borrowernumber,$title,$author,$publishercode,$note,$copyrightdate,$volumedesc,$publicationyear,$place,$isbn,$biblionumber) = @_;
+ my $dbh = C4::Context->dbh;
+
+ my $query = qq |
+ INSERT INTO suggestions
+ (status,suggestedby,title,author,publishercode,note,copyrightdate,
+ volumedesc,publicationyear,place,isbn,biblionumber)
+ VALUES ('ASKED',?,?,?,?,?,?,?,?,?,?,?)
+ |;
+ my $sth = $dbh->prepare($query);
+ $sth->execute($borrowernumber,$title,$author,$publishercode,$note,$copyrightdate,$volumedesc,$publicationyear,$place,$isbn,$biblionumber);
+}
+
+=head2 ModStatus
+
+=over 4
+
+&ModStatus($suggestionid,$status,$managedby,$biblionumber)
+
+Modify the status (status can be 'ASKED', 'ACCEPTED', 'REJECTED', 'ORDERED')
+and send a mail to notify the user that did the suggestion.
+
+Note that there is no function to modify a suggestion : only the status can be modified, thus the name of the function.
+
+=back
+
+=cut
+sub ModStatus {
+ my ($suggestionid,$status,$managedby,$biblionumber,$input) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth;
+ if ($managedby>0) {
+ if ($biblionumber) {
+ my $query = qq|
+ UPDATE suggestions
+ SET status=?,managedby=?,biblionumber=?
+ WHERE suggestionid=?
+ |;
+ $sth = $dbh->prepare($query);
+ $sth->execute($status,$managedby,$biblionumber,$suggestionid);
+ } else {
+ my $query = qq|
+ UPDATE suggestions
+ SET status=?,managedby=?
+ WHERE suggestionid=?
+ |;
+ $sth = $dbh->prepare($query);
+ $sth->execute($status,$managedby,$suggestionid);
+ }
+ } else {
+ if ($biblionumber) {
+ my $query = qq|
+ UPDATE suggestions
+ SET status=?,biblionumber=?
+ WHERE suggestionid=?
+ |;
+ $sth = $dbh->prepare($query);
+ $sth->execute($status,$biblionumber,$suggestionid);
+ }
+ else {
+ my $query = qq|
+ UPDATE suggestions
+ SET status=?
+ WHERE suggestionid=?
+ |;
+ $sth = $dbh->prepare($query);
+ $sth->execute($status,$suggestionid);
+ }
+ }
+ # check mail sending.
+ my $queryMail = qq|
+ SELECT suggestions.*,
+ boby.surname AS bysurname,
+ boby.firstname AS byfirstname,
+ boby.emailaddress AS byemail,
+ lib.surname AS libsurname,
+ lib.firstname AS libfirstname,
+ lib.emailaddress AS libemail
+ FROM suggestions
+ LEFT JOIN borrowers AS boby ON boby.borrowernumber=suggestedby
+ LEFT JOIN borrowers AS lib ON lib.borrowernumber=managedby
+ WHERE suggestionid=?
+ |;
+ $sth = $dbh->prepare($queryMail);
+ $sth->execute($suggestionid);
+ my $emailinfo = $sth->fetchrow_hashref;
+if ($emailinfo->{byemail}){
+ my $template = gettemplate("suggestion/mail_suggestion_$status.tmpl","intranet",$input);
+
+ $template->param(
+ byemail => $emailinfo->{byemail},
+ libemail => $emailinfo->{libemail},
+ status => $emailinfo->{status},
+ title => $emailinfo->{title},
+ author =>$emailinfo->{author},
+ libsurname => $emailinfo->{libsurname},
+ libfirstname => $emailinfo->{libfirstname},
+ byfirstname => $emailinfo->{byfirstname},
+ bysurname => $emailinfo->{bysurname},
+ );
+ my %mail = (
+ To => $emailinfo->{byemail},
+ From => $emailinfo->{libemail},
+ Subject => 'Koha suggestion',
+ Message => "".$template->output
+ );
+ sendmail(%mail);
+}
+}
+
+=head2 ConnectSuggestionAndBiblio
+
+=over 4
+&ConnectSuggestionAndBiblio($suggestionid,$biblionumber)
+
+connect a suggestion to an existing biblio
+
+=back
+
+=cut
+sub ConnectSuggestionAndBiblio {
+ my ($suggestionid,$biblionumber) = @_;
+ my $dbh=C4::Context->dbh;
+ my $query = qq |
+ UPDATE suggestions
+ SET biblionumber=?
+ WHERE suggestionid=?
+ |;
+ my $sth = $dbh->prepare($query);
+ $sth->execute($biblionumber,$suggestionid);
+}
+
+=head2 DelSuggestion
+
+=over 4
+
+&DelSuggestion($borrowernumber,$suggestionid)
+
+Delete a suggestion. A borrower can delete a suggestion only if he is its owner.
+
+=back
+
+=cut
+
+sub DelSuggestion {
+ my ($borrowernumber,$suggestionid) = @_;
+ my $dbh = C4::Context->dbh;
+ # check that the suggestion comes from the suggestor
+ my $query = qq |
+ SELECT suggestedby
+ FROM suggestions
+ WHERE suggestionid=?
+ |;
+ my $sth = $dbh->prepare($query);
+ $sth->execute($suggestionid);
+ my ($suggestedby) = $sth->fetchrow;
+ if ($suggestedby eq $borrowernumber) {
+ my $queryDelete = qq|
+ DELETE FROM suggestions
+ WHERE suggestionid=?
+ |;
+ $sth = $dbh->prepare($queryDelete);
+ $sth->execute($suggestionid);
+ }
+}
+
+1;
+__END__;
\ No newline at end of file
Index: Z3950.pm
===================================================================
RCS file: Z3950.pm
diff -N Z3950.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Z3950.pm 10 Mar 2007 01:35:34 -0000 1.1.2.1
@@ -0,0 +1,380 @@
+package C4::Z3950;
+
+# $Id: Z3950.pm,v 1.1.2.1 2007/03/10 01:35:34 tgarip1957 Exp $
+
+# Routines for handling Z39.50 lookups
+
+# Koha library project www.koha.org
+
+# Licensed under the GPL
+
+
+# Copyright 2000-2002 Katipo Communications
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+
+# standard or CPAN modules used
+
+# Koha modules used
+use C4::Context;
+use C4::Input;
+use C4::Biblio;
+
+#------------------
+
+require Exporter;
+
+use vars qw($VERSION @ISA @EXPORT);
+
+# set the version for version checking
+$VERSION = 0.01;
+
+=head1 NAME
+
+C4::Z3950 - Functions dealing with Z39.50 queries
+
+=head1 SYNOPSIS
+
+ use C4::Z3950;
+
+=head1 DESCRIPTION
+
+This module contains functions for looking up Z39.50 servers, and for
+entering Z39.50 lookup requests.
+
+=head1 FUNCTIONS
+
+=over 2
+
+=cut
+
+ at ISA = qw(Exporter);
+ at EXPORT = qw(
+ &getz3950servers
+ &z3950servername
+ &addz3950queue
+ &checkz3950searchdone
+);
+
+#------------------------------------------------
+=item getz3950servers
+
+ @servers= &getz3950servers(checked);
+
+Returns the list of declared z3950 servers
+
+C<$checked> should always be true (1) => returns only active servers.
+If 0 => returns all servers
+
+=cut
+sub getz3950servers {
+ my ($checked) = @_;
+ my $dbh = C4::Context->dbh;
+ my $sth;
+ if ($checked) {
+ $sth = $dbh->prepare("select * from z3950servers where checked=1");
+ } else {
+ $sth = $dbh->prepare("select * from z3950servers");
+ }
+ my @result;
+ while ( my ($host, $port, $db, $userid, $password,$servername) = $sth->fetchrow ) {
+ push @result, "$servername/$host\:$port/$db/$userid/$password";
+ } # while
+ return @result;
+}
+
+=item z3950servername
+
+ $name = &z3950servername($dbh, $server_id, $default_name);
+
+Looks up a Z39.50 server by ID number, and returns its full name. If
+the server is not found, returns C<$default_name>.
+
+C<$server_id> is the Z39.50 server ID to look up.
+
+C<$dbh> is ignored.
+
+=cut
+#'
+
+sub z3950servername {
+ # inputs
+ my ($srvid, # server id number
+ $default,)=@_;
+ # return
+ my $longname;
+ #----
+
+ my $dbh = C4::Context->dbh;
+
+ my $sti=$dbh->prepare("select name from z3950servers where id=?");
+
+ $sti->execute($srvid);
+ if ( ! $sti->err ) {
+ ($longname)=$sti->fetchrow;
+ }
+ if (! $longname) {
+ $longname="$default";
+ }
+ return $longname;
+} # sub z3950servername
+
+#---------------------------------------
+
+=item addz3950queue
+
+ $errmsg = &addz3950queue($query, $type, $request_id, @servers);
+
+Adds a Z39.50 search query for the Z39.50 server to look up.
+
+C<$query> is the term to search for.
+
+C<$type> is the query type, e.g. C<isbn>, C<lccn>, etc.
+
+C<$request_id> is a unique string that will identify this query.
+
+C<@servers> is a list of servers to query (obviously, this can be
+given either as an array, or as a list of scalars). Each element may
+be either a Z39.50 server ID from the z3950server table of the Koha
+database, the string C<DEFAULT> or C<CHECKED>, or a complete server
+specification containing a colon.
+
+C<DEFAULT> and C<CHECKED> are synonymous, and refer to those servers
+in the z3950servers table whose 'checked' field is set and non-NULL.
+
+Once the query has been submitted to the Z39.50 daemon,
+C<&addz3950queue> sends a SIGHUP to the daemon to tell it to process
+this new request.
+
+C<&addz3950queue> returns an error message. If it was successful, the
+error message is the empty string.
+
+=cut
+#'
+sub addz3950queue {
+ use strict;
+ # input
+ my (
+ $query, # value to look up
+ $type, # type of value ("isbn", "lccn", "title", "author", "keyword")
+ $requestid, # Unique value to prevent duplicate searches from multiple HTML form submits
+ @z3950list, # list of z3950 servers to query
+ )=@_;
+ # Returns:
+ my $error;
+
+ my (
+ $sth,
+ @serverlist,
+ $server,
+ $failed,
+ $servername,
+ );
+
+ # FIXME - Should be configurable, probably in /etc/koha.conf.
+ my $pidfile='/var/log/koha/processz3950queue.pid';
+
+ $error="";
+
+ my $dbh = C4::Context->dbh;
+ # list of servers: entry can be a fully qualified URL-type entry
+ # or simply just a server ID number.
+ foreach $server (@z3950list) {
+ if ($server =~ /:/ ) {
+ push @serverlist, $server;
+ } elsif ($server eq 'DEFAULT' || $server eq 'CHECKED' ) {
+ $sth=$dbh->prepare("select host,port,db,userid,password ,name,syntax from z3950servers where checked <> 0 ");
+ $sth->execute;
+ while ( my ($host, $port, $db, $userid, $password,$servername,$syntax) = $sth->fetchrow ) {
+ push @serverlist, "$servername/$host\:$port/$db/$userid/$password/$syntax";
+ } # while
+ } else {
+ $sth=$dbh->prepare("select host,port,db,userid,password,syntax from z3950servers where id=? ");
+ $sth->execute($server);
+ my ($host, $port, $db, $userid, $password,$syntax) = $sth->fetchrow;
+ push @serverlist, "$server/$host\:$port/$db/$userid/$password/$syntax";
+ }
+ }
+
+ my $serverlist='';
+
+ $serverlist = join("|", @serverlist);
+# chop $serverlist;
+
+ # FIXME - Is this test supposed to test whether @serverlist is
+ # empty? If so, then a) there are better ways to do that in
+ # Perl (e.g., "if (@serverlist eq ())"), and b) it doesn't
+ # work anyway, since it checks whether $serverlist is composed
+ # of one or more spaces, which is never the case, not even
+ # when there are 0 or 1 elements in @serverlist.
+ if ( $serverlist !~ /^ +$/ ) {
+ # Don't allow reinsertion of the same request identifier.
+ $sth=$dbh->prepare("select identifier from z3950queue
+ where identifier=?");
+ $sth->execute($requestid);
+ if ( ! $sth->rows) {
+ $sth=$dbh->prepare("insert into z3950queue (term,type,servers, identifier) values (?, ?, ?, ?)");
+ $sth->execute($query, $type, $serverlist, $requestid);
+ if ( -r $pidfile ) {
+ # FIXME - Perl is good at opening files. No need to
+ # spawn a separate 'cat' process.
+ my $pid=`cat $pidfile`;
+ chomp $pid;
+ warn "PID : $pid";
+ # Kill -HUP the Z39.50 daemon to tell it to process
+ # this query.
+ my $processcount=kill 1, $pid;
+ if ($processcount==0) {
+ $error.="Z39.50 search daemon error: no process signalled. ";
+ }
+ } else {
+ # FIXME - Error-checking like this should go close
+ # to the test.
+ $error.="No Z39.50 search daemon running: no file $pidfile. ";
+ } # if $pidfile
+ } else {
+ # FIXME - Error-checking like this should go close
+ # to the test.
+ $error.="Duplicate request ID $requestid. ";
+ } # if rows
+ } else {
+ # FIXME - Error-checking like this should go close to the
+ # test. I.e.,
+ # return "No Z39.50 search servers specified. "
+ # if @serverlist eq ();
+
+ # server list is empty
+ $error.="No Z39.50 search servers specified. ";
+ } # if serverlist empty
+
+ return $error;
+
+} # sub addz3950queue
+
+=item &checkz3950searchdone
+
+ $numberpending= & &checkz3950searchdone($random);
+
+Returns the number of pending z3950 requests
+
+C<$random> is the random z3950 query number.
+
+=cut
+sub checkz3950searchdone {
+ my ($z3950random) = @_;
+ my $dbh = C4::Context->dbh;
+ # first, check that the deamon already created the requests...
+ my $sth = $dbh->prepare("select count(*) from z3950queue,z3950results where z3950queue.id = z3950results.queryid and z3950queue.identifier=?");
+ $sth->execute($z3950random);
+ my ($result) = $sth->fetchrow;
+ if ($result eq 0) { # search not yet begun => should be searches to do !
+ return "??";
+ }
+ # second, count pending requests
+ $sth = $dbh->prepare("select count(*) from z3950queue,z3950results where z3950queue.id = z3950results.queryid and z3950results.enddate is null and z3950queue.identifier=?");
+ $sth->execute($z3950random);
+ ($result) = $sth->fetchrow;
+ return $result;
+}
+
+1;
+__END__
+
+=back
+
+=head1 AUTHOR
+
+Koha Developement team <info at koha.org>
+
+=cut
+
+#--------------------------------------
+# $Log: Z3950.pm,v $
+# Revision 1.1.2.1 2007/03/10 01:35:34 tgarip1957
+# fresh files for rel_TG
+#
+# Revision 1.13 2006/09/06 16:21:03 tgarip1957
+# Clean up before final commits
+#
+# Revision 1.10 2003/10/01 15:08:14 tipaul
+# fix fog bug #622 : processz3950queue fails
+#
+# Revision 1.9 2003/04/29 16:50:51 tipaul
+# really proud of this commit :-)
+# z3950 search and import seems to works fine.
+# Let me explain how :
+# * a "search z3950" button is added in the addbiblio template.
+# * when clicked, a popup appears and z3950/search.pl is called
+# * z3950/search.pl calls addz3950search in the DB
+# * the z3950 daemon retrieve the records and stores them in z3950results AND in marc_breeding table.
+# * as long as there as searches pending, the popup auto refresh every 2 seconds, and says how many searches are pending.
+# * when the user clicks on a z3950 result => the parent popup is called with the requested biblio, and auto-filled
+#
+# Note :
+# * character encoding support : (It's a nightmare...) In the z3950servers table, a "encoding" column has been added. You can put "UNIMARC" or "USMARC" in this column. Depending on this, the char_decode in C4::Biblio.pm replaces marc-char-encode by an iso 8859-1 encoding. Note that in the breeding import this value has been added too, for a better support.
+# * the marc_breeding and z3950* tables have been modified : they have an encoding column and the random z3950 number is stored too for convenience => it's the key I use to list only requested biblios in the popup.
+#
+# Revision 1.8 2003/04/29 08:09:45 tipaul
+# z3950 support is coming...
+# * adding a syntax column in z3950 table = this column will say wether the z3950 must be called with PerferedRecordsyntax => USMARC or PerferedRecordsyntax => UNIMARC. I tried some french UNIMARC z3950 servers, and some only send USMARC, some only UNIMARC, some can answer with both.
+# Note this is a 1st draft. More to follow (today ? I hope).
+#
+# Revision 1.7 2003/02/19 01:01:06 wolfpac444
+# Removed the unecessary $dbh argument from being passed.
+# Resolved a few minor FIXMEs.
+#
+# Revision 1.6 2002/10/13 08:30:53 arensb
+# Deleted unused variables.
+# Removed trailing whitespace.
+#
+# Revision 1.5 2002/10/13 06:13:23 arensb
+# Removed bogus #! line (this isn't a script!)
+# Removed unused global variables.
+# Added POD.
+# Added some explanatory comments.
+# Added some FIXME comments.
+#
+# Revision 1.4 2002/10/11 12:35:35 arensb
+# Replaced &requireDBI with C4::Context->dbh
+#
+# Revision 1.3 2002/08/14 18:12:52 tonnesen
+# Added copyright statement to all .pl and .pm files
+#
+# Revision 1.2 2002/07/02 20:31:33 tonnesen
+# module added from rel-1-2 branch
+#
+# Revision 1.1.2.5 2002/06/29 17:33:47 amillar
+# Allow DEFAULT as input to addz3950search.
+# Check for existence of pid file (cat crashed otherwise).
+# Return error messages in addz3950search.
+#
+# Revision 1.1.2.4 2002/06/28 18:07:27 tonnesen
+# marcimport.pl will print an error message if it can not signal the
+# processz3950queue program. The message contains instructions for starting the
+# daemon.
+#
+# Revision 1.1.2.3 2002/06/28 17:45:39 tonnesen
+# z3950queue now listens for a -HUP signal before processing the queue. Z3950.pm
+# sends the -HUP signal when queries are added to the queue.
+#
+# Revision 1.1.2.2 2002/06/26 20:54:31 tonnesen
+# use warnings breaks on perl 5.005...
+#
+# Revision 1.1.2.1 2002/06/26 07:26:41 amillar
+# New module for Z39.50 searching
+#
More information about the Koha-cvs
mailing list