From srdjan at catalyst.net.nz Wed Feb 1 00:46:55 2012 From: srdjan at catalyst.net.nz (Srdjan Jankovic) Date: Wed, 1 Feb 2012 12:46:55 +1300 Subject: [Koha-patches] [PATCH] bug_7477: Copy holidays from one branch to another In-Reply-To: References: Message-ID: <1328053615-11993-1-git-send-email-srdjan@catalyst.net.nz> --- C4/Calendar.pm | 98 ++++++++++++++------ .../prog/en/modules/tools/holidays.tt | 15 +++ tools/copy-holidays.pl | 40 ++++++++ 3 files changed, 125 insertions(+), 28 deletions(-) create mode 100755 tools/copy-holidays.pl diff --git a/C4/Calendar.pm b/C4/Calendar.pm index dc9037b..741e309 100644 --- a/C4/Calendar.pm +++ b/C4/Calendar.pm @@ -20,34 +20,11 @@ use warnings; use vars qw($VERSION @EXPORT); use Carp; -use Date::Calc qw( Date_to_Days ); +use Date::Calc qw( Date_to_Days Today); use C4::Context; -BEGIN { - # set the version for version checking - $VERSION = 3.01; - require Exporter; - @EXPORT = qw( - &get_week_days_holidays - &get_day_month_holidays - &get_exception_holidays - &get_single_holidays - &insert_week_day_holiday - &insert_day_month_holiday - &insert_single_holiday - &insert_exception_holiday - &ModWeekdayholiday - &ModDaymonthholiday - &ModSingleholiday - &ModExceptionholiday - &delete_holiday - &isHoliday - &addDate - &daysBetween - ); -} - +use constant ISO_DATE_FORMAT => "%04d-%02d-%02d"; =head1 NAME C4::Calendar::Calendar - Koha module dealing with holidays. @@ -123,7 +100,7 @@ sub _init { $exception_holidays{"$year/$month/$day"}{title} = $title; $exception_holidays{"$year/$month/$day"}{description} = $description; $exception_holidays{"$year/$month/$day"}{date} = - sprintf("%04d-%02d-%02d", $year, $month, $day); + sprintf(ISO_DATE_FORMAT, $year, $month, $day); } $self->{'exception_holidays'} = \%exception_holidays; @@ -133,7 +110,7 @@ sub _init { $single_holidays{"$year/$month/$day"}{title} = $title; $single_holidays{"$year/$month/$day"}{description} = $description; $single_holidays{"$year/$month/$day"}{date} = - sprintf("%04d-%02d-%02d", $year, $month, $day); + sprintf(ISO_DATE_FORMAT, $year, $month, $day); } $self->{'single_holidays'} = \%single_holidays; return $self; @@ -283,6 +260,9 @@ sub insert_single_holiday { my $self = shift @_; my %options = @_; + @options{qw(year month day)} = ( $options{date} =~ m/(\d+)-(\d+)-(\d+)/o ) + if $options{date} && !$options{day}; + my $dbh = C4::Context->dbh(); my $isexception = 0; my $insertHoliday = $dbh->prepare("insert into special_holidays (id,branchcode,day,month,year,isexception,title,description) values ('', ?,?,?,?,?,?,?)"); @@ -318,6 +298,9 @@ sub insert_exception_holiday { my $self = shift @_; my %options = @_; + @options{qw(year month day)} = ( $options{date} =~ m/(\d+)-(\d+)-(\d+)/o ) + if $options{date} && !$options{day}; + my $dbh = C4::Context->dbh(); my $isexception = 1; my $insertException = $dbh->prepare("insert into special_holidays (id,branchcode,day,month,year,isexception,title,description) values ('', ?,?,?,?,?,?,?)"); @@ -567,6 +550,65 @@ sub isHoliday { } +=head2 copy_to_branch + + $calendar->copy_to_branch($target_branch) + +=cut + +sub copy_to_branch { + my ($self, $target_branch) = @_; + + croak "No target_branch" unless $target_branch; + + my $target_calendar = C4::Calendar->new(branchcode => $target_branch); + + my ($y, $m, $d) = Today(); + my $today = sprintf ISO_DATE_FORMAT, $y,$m,$d; + + $target_calendar->insert_week_day_holiday(%$_) + foreach values %{ $self->get_week_days_holidays }; + $target_calendar->insert_day_month_holiday(%$_) + foreach values %{ $self->get_day_month_holidays }; + $target_calendar->insert_exception_holiday(%$_) + foreach grep { $_->{date} gt $today } values %{ $self->get_exception_holidays }; + $target_calendar->insert_single_holiday(%$_) + foreach grep { $_->{date} gt $today } values %{ $self->get_single_holidays }; + + return 1; +} + +=head2 daysBetween + + my $daysBetween = $calendar->daysBetween($startdate, $enddate) + +C<$startdate> and C<$enddate> are C4::Dates objects that define the interval. + +Returns the number of non-holiday days in the interval. +useDaysMode syspref has no effect here. +=cut + +sub daysBetween ($$$) { + my $self = shift or return undef; + my $startdate = shift or return undef; + my $enddate = shift or return undef; + my ($yearFrom,$monthFrom,$dayFrom) = split("-",$startdate->output('iso')); + my ($yearTo, $monthTo, $dayTo ) = split("-", $enddate->output('iso')); + if (Date_to_Days($yearFrom,$monthFrom,$dayFrom) > Date_to_Days($yearTo,$monthTo,$dayTo)) { + return 0; + # we don't go backwards ( FIXME - handle this error better ) + } + my $count = 0; + while (1) { + ($yearFrom != $yearTo or $monthFrom != $monthTo or $dayFrom != $dayTo) or last; # if they all match, it's the last day + unless ($self->isHoliday($dayFrom, $monthFrom, $yearFrom)) { + $count++; + } + ($yearFrom, $monthFrom, $dayFrom) = &Date::Calc::Add_Delta_Days($yearFrom, $monthFrom, $dayFrom, 1); + } + return($count); +} + =head2 addDate my ($day, $month, $year) = $calendar->addDate($date, $offset) @@ -601,7 +643,7 @@ sub addDate { } else { ## ($daysMode eq 'Days') ($year, $month, $day) = &Date::Calc::Add_Delta_Days($year, $month, $day, $offset ); } - return(C4::Dates->new( sprintf("%04d-%02d-%02d",$year,$month,$day),'iso')); + return(C4::Dates->new( sprintf(ISO_DATE_FORMAT,$year,$month,$day),'iso')); } =head2 daysBetween diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/holidays.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/holidays.tt index 686e3af..6ee87df 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/holidays.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/holidays.tt @@ -388,6 +388,21 @@ + +
+
+ + + + +
+
+
diff --git a/tools/copy-holidays.pl b/tools/copy-holidays.pl new file mode 100755 index 0000000..9de4b8c --- /dev/null +++ b/tools/copy-holidays.pl @@ -0,0 +1,40 @@ +#!/usr/bin/perl + +# Copyright 2012 Catalyst IT +# +# 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use strict; +use warnings; + +use CGI; + +use C4::Auth; +use C4::Output; + + +use C4::Calendar; + +my $input = new CGI; +my $dbh = C4::Context->dbh(); + +my $branchcode = $input->param('branchcode'); +my $from_branchcode = $input->param('from_branchcode'); + +C4::Calendar->new(branchcode => $from_branchcode)->copy_to_branch($branchcode) if $from_branchcode && $branchcode; + +print $input->redirect("/cgi-bin/koha/tools/holidays.pl?branch=".($branchcode || $from_branchcode)); + -- 1.6.5 From srdjan at catalyst.net.nz Wed Feb 1 03:19:03 2012 From: srdjan at catalyst.net.nz (Srdjan Jankovic) Date: Wed, 1 Feb 2012 15:19:03 +1300 Subject: [Koha-patches] [PATCH] bug_7458: A call number plugin In-Reply-To: References: Message-ID: <1328062743-28298-1-git-send-email-srdjan@catalyst.net.nz> --- cataloguing/value_builder/callnumber-KU.pl | 140 ++++++++++++++++++++++++++++ 1 files changed, 140 insertions(+), 0 deletions(-) create mode 100755 cataloguing/value_builder/callnumber-KU.pl diff --git a/cataloguing/value_builder/callnumber-KU.pl b/cataloguing/value_builder/callnumber-KU.pl new file mode 100755 index 0000000..72fea3f --- /dev/null +++ b/cataloguing/value_builder/callnumber-KU.pl @@ -0,0 +1,140 @@ +#!/usr/bin/perl + +# Copyright 2012 CatalystIT Ltd +# +# 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use strict; +use warnings; +use C4::Auth; +use CGI; +use C4::Context; + +=head1 DESCRIPTION + +Is used for callnumber computation. + +User must supply a letter prefix (unspecified length) followed by an empty space followed by a "number". +"Number" is 4 character long, and is either a number sequence which is 0 padded +or two letters which are 01 padded. +If input does not conform with this format any processing is omitted. + +Some examples of legal values that trigger auto allocation: + +AAA 0 - returns first unused number AAA 0xxx starting with AAA 0000 +BBB 12 - returns first unused number BBB 12xx starting with BBB 1200 +CCC QW - returns first unused number CCC QWxx starting with CCC QW01 + +=cut + +sub plugin_parameters { +} + +sub plugin_javascript { + my ($dbh,$record,$tagslib,$field_number,$tabloop) = @_; + my $res=" + + "; + + return ($field_number,$res); +} + +my $BASE_CALLNUMBER_RE = qr/^(\w+) (\w+)$/; +sub plugin { + my ($input) = @_; + my $code = $input->param('code'); + + my ($template, $loggedinuser, $cookie) = get_template_and_user({ + template_name => "cataloguing/value_builder/ajax.tmpl", + query => $input, + type => "intranet", + authnotrequired => 0, + flagsrequired => {editcatalogue => '*'}, + debug => 1, + }); + + my $ret; + my ($alpha, $num) = ($code =~ $BASE_CALLNUMBER_RE); + if (defined $num) { # otherwise no point + my ($num_alpha, $num_num) = ($num =~ m/^(\D+)?(\d+)?$/); + $num_alpha ||= ''; + my $pad_len = 4 - length($num); + + if ($pad_len > 0) { + my $num_padded = $num_num; + if ($num_alpha) { + $num_padded .= "0" x ($pad_len - 1) if $pad_len > 1; + $num_padded .= "1"; + } else { + $num_padded .= "0" x $pad_len; + } + my $padded = "$alpha $num_alpha" . $num_padded; + + my $dbh = C4::Context->dbh; + if ( my $first = $dbh->selectrow_array("SELECT itemcallnumber + FROM items + WHERE itemcallnumber = ?", undef, $padded) ) { + my $icn = $dbh->selectcol_arrayref("SELECT itemcallnumber + FROM items + WHERE itemcallnumber LIKE ? + AND itemcallnumber > ? + ORDER BY itemcallnumber", undef, "$alpha $num_alpha%", $first); + my $next = $num_padded + 1; + my $len = length($num_padded); + foreach (@$icn) { + my ($num1) = ( m/(\d+)$/o ); + if ($num1 > $next) { # a hole in numbering found, stop + last; + } + $next++; + } + $ret = "$alpha $num_alpha" . sprintf("%0${len}d", $next) if length($next) <= $len; # no overflow + } + else { + $ret = $padded; + } + } + } + + $template->param( + return => $ret || $code + ); + output_html_with_http_headers $input, $cookie, $template->output; +} + +1; -- 1.6.5 From adrien.saurat at biblibre.com Wed Feb 1 16:11:58 2012 From: adrien.saurat at biblibre.com (Adrien Saurat) Date: Wed, 1 Feb 2012 16:11:58 +0100 Subject: [Koha-patches] [PATCH] Bug 7488: cleans logs for moremember.pl Message-ID: <1328109118-14652-1-git-send-email-adrien.saurat@biblibre.com> --- C4/Members/Messaging.pm | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/C4/Members/Messaging.pm b/C4/Members/Messaging.pm index 2b39f11..ae77be0 100644 --- a/C4/Members/Messaging.pm +++ b/C4/Members/Messaging.pm @@ -213,6 +213,7 @@ END_SQL $choices->{ $row->{'message_name'} }->{'message_name'} = $row->{'message_name'}; $choices->{ $row->{'message_name'} }->{'takes_days'} = $row->{'takes_days'}; $choices->{ $row->{'message_name'} }->{'has_digest'} = 1 if $row->{'is_digest'}; + if ( not defined ($row->{'message_transport_type'}) ) { $row->{'message_transport_type'} = '' } $choices->{ $row->{'message_name'} }->{'transport_' . $row->{'message_transport_type'}} = ' '; } -- 1.7.4.1 From gcollum at gmail.com Wed Feb 1 16:37:08 2012 From: gcollum at gmail.com (Garry Collum) Date: Wed, 1 Feb 2012 10:37:08 -0500 Subject: [Koha-patches] [PATCH] Bug 6984 - Holds statistics doesn't work. Message-ID: <1328110628-2961-1-git-send-email-gcollum@gmail.com> This patch fixes several errors in reserves_stats.pl and reserves_stats.tt. Testing - To test this patch, data must be in either the reserves table or old_reserves or both. The following SQL will give you the raw data that is used by the report. SELECT priority, found, reservedate, notificationdate, reminderdate, waitingdate, cancellationdate, borrowers.categorycode, items.itype, reserves.branchcode, holdingbranch, items.homebranch, items.ccode, items.location, items.itemcallnumber, borrowers.sort1, borrowers.sort2 FROM reserves LEFT JOIN borrowers on (borrowers.borrowernumber = reserves.borrowernumber) LEFT JOIN items on (items.itemnumber = reserves.itemnumber) UNION SELECT priority, found, reservedate, notificationdate, reminderdate, waitingdate, cancellationdate, borrowers.categorycode, items.itype, old_reserves.branchcode, holdingbranch, items.homebranch, items.ccode, items.location, items.itemcallnumber, borrowers.sort1, borrowers.sort2 FROM old_reserves LEFT JOIN borrowers on (borrowers.borrowernumber = old_reserves.borrowernumber) LEFT JOIN items on (items.itemnumber = old_reserves.itemnumber) To test the notificationdate and reminderdate, I added data to the old_reserves table, since I have never run notices on my test machine. Ex: UPDATE old_reserves SET notificationdate = "2012-01-29", reminderdate = "2012-01-29" WHERE timestamp = "2012-01-29 20:09:34"; --- .../prog/en/modules/reports/reserves_stats.tt | 28 +++--- reports/reserves_stats.pl | 89 ++++++++++++-------- 2 files changed, 69 insertions(+), 48 deletions(-) diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/reports/reserves_stats.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/reports/reserves_stats.tt index 6f5865b..f5d03f5 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/reports/reserves_stats.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/reports/reserves_stats.tt @@ -89,18 +89,18 @@ - Asked - Processing - Waiting - Satisfied - Cancelled + Asked + Processing + Waiting + Satisfied + Cancelled Hold Date - + Show Calendar Required
[% INCLUDE 'date-format.inc' %]
- - +
  • + + +
  • +
    diff --git a/serials/checkexpiration.pl b/serials/checkexpiration.pl index 02a4fbc..13ad042 100755 --- a/serials/checkexpiration.pl +++ b/serials/checkexpiration.pl @@ -68,6 +68,7 @@ my ( $template, $loggedinuser, $cookie ) = get_template_and_user ( my $title = $query->param('title'); my $issn = $query->param('issn'); my $date = format_date_in_iso($query->param('date')); +my $showexpiredtoday = $query->param('showexpiredtoday'); if ($date) { my @subscriptions = GetSubscriptions( $title, $issn ); @@ -78,9 +79,10 @@ if ($date) { my $expirationdate = GetExpirationDate($subscriptionid); $subscription->{expirationdate} = $expirationdate; - next if $expirationdate !~ /\d{4}-\d{2}-\d{2}/; # next if not in ISO format. + next if !$expirationdate || $expirationdate !~ /\d{4}-\d{2}-\d{2}/; # next if not in ISO format. if ( Date_to_Days(split "-",$expirationdate) < Date_to_Days(split "-",$date) && - Date_to_Days(split "-",$expirationdate) > Date_to_Days(&Today) ) { + (($showexpiredtoday && $showexpiredtoday eq 'on') || (Date_to_Days(split "-",$expirationdate) > Date_to_Days(&Today))) + ) { $subscription->{expirationdate}=format_date($subscription->{expirationdate}); push @subscriptions_loop,$subscription; } @@ -89,6 +91,7 @@ if ($date) { $template->param ( title => $title, issn => $issn, + showexpiredtoday => $showexpiredtoday, numsubscription => scalar @subscriptions_loop, date => format_date($date), subscriptions_loop => \@subscriptions_loop, -- 1.7.4.1 From stephane.delaune at biblibre.com Fri Feb 3 17:05:05 2012 From: stephane.delaune at biblibre.com (=?UTF-8?q?St=C3=A9phane=20Delaune?=) Date: Fri, 3 Feb 2012 17:05:05 +0100 Subject: [Koha-patches] [PATCH] Bug 4032:XSLT systempreference takes a path to file rather than YesNo Message-ID: <1328285105-5921-1-git-send-email-stephane.delaune@biblibre.com> --- C4/Search.pm | 3 +- C4/VirtualShelves/Page.pm | 2 +- C4/XSLT.pm | 48 +++++++++++--------- catalogue/detail.pl | 2 +- installer/data/mysql/sysprefs.sql | 8 ++-- installer/data/mysql/updatedatabase.pl | 31 +++++++++++++ .../prog/en/modules/admin/preferences/opac.pref | 12 ++--- .../en/modules/admin/preferences/staff_client.pref | 12 ++--- opac/opac-detail.pl | 3 +- 9 files changed, 74 insertions(+), 47 deletions(-) diff --git a/C4/Search.pm b/C4/Search.pm index e86bb26..43a19a5 100644 --- a/C4/Search.pm +++ b/C4/Search.pm @@ -1839,8 +1839,7 @@ sub searchResults { $oldbiblio->{XSLTResultsRecord} = XSLTParse4Display($oldbiblio->{biblionumber}, $marcrecord, - 'Results', - $search_context, + C4::Context->preference("OPACXSLTResultsDisplay"), 1, # clean up the problematic ampersand entities that Zebra outputs \@hiddenitems ); diff --git a/C4/VirtualShelves/Page.pm b/C4/VirtualShelves/Page.pm index cfa4f60..d30db85 100644 --- a/C4/VirtualShelves/Page.pm +++ b/C4/VirtualShelves/Page.pm @@ -208,7 +208,7 @@ sub shelfpage ($$$$$) { my $biblionumber = $this_item->{'biblionumber'}; my $record = GetMarcBiblio($biblionumber); $this_item->{XSLTBloc} = - XSLTParse4Display($biblionumber, $record, 'Results', 'opac') + XSLTParse4Display($biblionumber, $record, C4::Context->preference("OPACXSLTResultsDisplay")) if C4::Context->preference("OPACXSLTResultsDisplay") && $type eq 'opac'; # the virtualshelfcontents table does not store these columns nor are they retrieved from the items diff --git a/C4/XSLT.pm b/C4/XSLT.pm index 06dfaf4..a64ffe3 100755 --- a/C4/XSLT.pm +++ b/C4/XSLT.pm @@ -3,6 +3,7 @@ package C4::XSLT; # # Parts Copyright Katrin Fischer 2011 # Parts Copyright ByWater Solutions 2011 +# Parts Copyright Biblibre 2012 # # This file is part of Koha. # @@ -32,6 +33,7 @@ use C4::Reserves; use Encode; use XML::LibXML; use XML::LibXSLT; +use LWP::Simple; use vars qw($VERSION @ISA @EXPORT); @@ -41,6 +43,7 @@ BEGIN { @ISA = qw(Exporter); @EXPORT = qw( &XSLTParse4Display + &GetURI ); } @@ -50,6 +53,19 @@ C4::XSLT - Functions for displaying XSLT-generated content =head1 FUNCTIONS +=head2 GetURI + +GetURI file and returns the xslt as a string + +=cut + +sub GetURI { + my ($uri) = @_; + my $string; + $string = get $uri ; + return $string; +} + =head2 transformMARCXML4XSLT Replaces codes with authorized values in a MARC::Record object @@ -121,8 +137,7 @@ sub getAuthorisedValues4MARCSubfields { my $stylesheet; sub XSLTParse4Display { - my ( $biblionumber, $orig_record, $xsl_suffix, $interface, $fixamps, $hidden_items ) = @_; - $interface = 'opac' unless $interface; + my ( $biblionumber, $orig_record, $xslfilename, $fixamps, $hidden_items ) = @_; # grab the XML, run it through our stylesheet, push it out to the browser my $record = transformMARCXML4XSLT($biblionumber, $orig_record); #return $record->as_formatted(); @@ -153,29 +168,20 @@ sub XSLTParse4Display { # don't die when you find &, >, etc $parser->recover_silently(0); my $source = $parser->parse_string($xmlrecord); - unless ( $stylesheet ) { + unless ( $stylesheet->{$xslfilename} ) { my $xslt = XML::LibXSLT->new(); - my $xslfile; - if ($interface eq 'intranet') { - $xslfile = C4::Context->config('intrahtdocs') . - '/' . C4::Context->preference("template") . - '/' . C4::Templates::_current_language() . - '/xslt/' . - C4::Context->preference('marcflavour') . - "slim2intranet$xsl_suffix.xsl"; + my $style_doc; + if ( $xslfilename =~ /http:/ ) { + my $xsltstring = GetURI($xslfilename); + $style_doc = $parser->parse_string($xsltstring); } else { - $xslfile = C4::Context->config('opachtdocs') . - '/' . C4::Context->preference("opacthemes") . - '/' . C4::Templates::_current_language() . - '/xslt/' . - C4::Context->preference('marcflavour') . - "slim2OPAC$xsl_suffix.xsl"; + use Cwd; + $style_doc = $parser->parse_file($xslfilename); } - my $style_doc = $parser->parse_file($xslfile); - $stylesheet = $xslt->parse_stylesheet($style_doc); + $stylesheet->{$xslfilename} = $xslt->parse_stylesheet($style_doc); } - my $results = $stylesheet->transform($source); - my $newxmlrecord = $stylesheet->output_string($results); + my $results = $stylesheet->{$xslfilename}->transform($source); + my $newxmlrecord = $stylesheet->{$xslfilename}->output_string($results); return $newxmlrecord; } diff --git a/catalogue/detail.pl b/catalogue/detail.pl index db38551..1d3155d 100755 --- a/catalogue/detail.pl +++ b/catalogue/detail.pl @@ -84,7 +84,7 @@ my $marcflavour = C4::Context->preference("marcflavour"); # XSLT processing of some stuff if (C4::Context->preference("XSLTDetailsDisplay") ) { $template->param('XSLTDetailsDisplay' =>'1', - 'XSLTBloc' => XSLTParse4Display($biblionumber, $record, 'Detail','intranet') ); + 'XSLTBloc' => XSLTParse4Display($biblionumber, $record, C4::Context->preference("XSLTDetailsDisplay")) ); } $template->param( 'SpineLabelShowPrintOnBibDetails' => C4::Context->preference("SpineLabelShowPrintOnBibDetails") ); diff --git a/installer/data/mysql/sysprefs.sql b/installer/data/mysql/sysprefs.sql index 5e3d79d..4c06fe0 100755 --- a/installer/data/mysql/sysprefs.sql +++ b/installer/data/mysql/sysprefs.sql @@ -218,10 +218,10 @@ INSERT INTO `systempreferences` (variable,value,options,explanation,type) VALUES INSERT INTO `systempreferences` (variable,value,options,explanation,type) VALUES('OPACShelfBrowser','1','','Enable/disable Shelf Browser on item details page. WARNING: this feature is very resource consuming on collections with large numbers of items.','YesNo'); INSERT INTO `systempreferences` (variable,value,options,explanation,type) VALUES -('OPACXSLTDetailsDisplay','0','','Enable XSL stylesheet control over details page display on OPAC','YesNo'), -('OPACXSLTResultsDisplay','0','','Enable XSL stylesheet control over results page display on OPAC','YesNo'), -('XSLTDetailsDisplay','0','','Enable XSL stylesheet control over details page display on intranet','YesNo'), -('XSLTResultsDisplay','0','','Enable XSL stylesheet control over results page display on intranet','YesNo'); +('OPACXSLTDetailsDisplay','','','Enable XSL stylesheet control over details page display on OPAC','Free'), +('OPACXSLTResultsDisplay','','','Enable XSL stylesheet control over results page display on OPAC','Free'), +('XSLTDetailsDisplay','','','Enable XSL stylesheet control over details page display on intranet','Free'), +('XSLTResultsDisplay','','','Enable XSL stylesheet control over results page display on intranet','Free'); INSERT INTO `systempreferences` (variable,value,options,explanation,type) VALUES('AdvancedSearchTypes','itemtypes','itemtypes|ccode','Select which set of fields comprise the Type limit in the advanced search','Choice'); INSERT INTO `systempreferences` (variable,value,options,explanation,type) VALUES('AllowOnShelfHolds', '0', '', 'Allow hold requests to be placed on items that are not on loan', 'YesNo'); INSERT INTO `systempreferences` (variable,value,options,explanation,type) VALUES('AllowHoldsOnDamagedItems', '1', '', 'Allow hold requests to be placed on damaged items', 'YesNo'); diff --git a/installer/data/mysql/updatedatabase.pl b/installer/data/mysql/updatedatabase.pl index 099dfb9..bd6a79e 100755 --- a/installer/data/mysql/updatedatabase.pl +++ b/installer/data/mysql/updatedatabase.pl @@ -37,6 +37,7 @@ use Getopt::Long; use C4::Context; use C4::Installer; use C4::Dates; +use C4::Templates; use MARC::Record; use MARC::File::XML ( BinaryEncoding => 'utf8' ); @@ -4663,6 +4664,36 @@ ENDOFRENEWAL print "Upgrade to $DBversion done (Added a system preference to allow renewal of Patron account either from todays date or from existing expiry date in the patrons account.)\n"; SetVersion($DBversion); } + +$DBversion = "XXX"; +if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) { + my $countXSLTDetailsDisplay = 0; + my $valueXSLTDetailsDisplay = ""; + my $valueXSLTResultsDisplay = ""; + my $valueOPACXSLTDetailsDisplay = ""; + my $valueOPACXSLTResultsDisplay = ""; + #the line below test if database comes from a BibLibre's branch + $countXSLTDetailsDisplay = $dbh->do('SELECT 1 FROM `systempreferences` WHERE `variable`="IntranetXSLTDetailsDisplay"'); + if ($countXSLTDetailsDisplay > 0) + { + #the two lines below will only be used to update the databases from the BibLibre's branch. They will not affect the others + $dbh->do(q|UPDATE `systempreferences` SET `variable`="XSLTDetailsDisplay" WHERE `variable`="IntranetXSLTDetailsDisplay"|); + $dbh->do(q|UPDATE `systempreferences` SET `variable`="XSLTResultsDisplay" WHERE `variable`="IntranetXSLTResultsDisplay"|); + } + else + { + $valueXSLTDetailsDisplay = C4::Context->config('intrahtdocs').'/'.C4::Context->preference("template").'/'.C4::Templates::_current_language().'/xslt/'.C4::Context->preference('marcflavour')."slim2intranetDetail.xsl" if (C4::Context->preference("XSLTDetailsDisplay")); + $valueXSLTResultsDisplay = C4::Context->config('intrahtdocs').'/'.C4::Context->preference("template").'/'.C4::Templates::_current_language().'/xslt/'.C4::Context->preference('marcflavour')."slim2intranetResults.xsl" if (C4::Context->preference("XSLTResultsDisplay")); + $valueOPACXSLTDetailsDisplay = C4::Context->config('opachtdocs').'/'.C4::Context->preference("opacthemes").'/'.C4::Templates::_current_language().'/xslt/'.C4::Context->preference('marcflavour')."slim2OPACDetail.xsl" if (C4::Context->preference("OPACXSLTDetailsDisplay")); + $valueOPACXSLTResultsDisplay = C4::Context->config('opachtdocs').'/'.C4::Context->preference("opacthemes").'/'.C4::Templates::_current_language().'/xslt/'.C4::Context->preference('marcflavour')."slim2OPACResults.xsl" if (C4::Context->preference("OPACXSLTResultsDisplay")); + $dbh->do("UPDATE systempreferences SET type='Free', value=\"$valueXSLTDetailsDisplay\" WHERE variable='XSLTDetailsDisplay'"); + $dbh->do("UPDATE systempreferences SET type='Free', value=\"$valueXSLTResultsDisplay\" WHERE variable='XSLTResultsDisplay'"); + $dbh->do("UPDATE systempreferences SET type='Free', value=\"$valueOPACXSLTDetailsDisplay\" WHERE variable='OPACXSLTDetailsDisplay'"); + $dbh->do("UPDATE systempreferences SET type='Free', value=\"$valueOPACXSLTResultsDisplay\" WHERE variable='OPACXSLTResultsDisplay'"); + } + print "XSLT systempreference takes a path to file rather than YesNo\n"; + SetVersion($DBversion); +} =head1 FUNCTIONS =head2 DropAllForeignKeys($table) diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref index d6ae2b2..e71b4f4 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref @@ -48,17 +48,13 @@ OPAC: no: Show - lost items on search and detail pages. - - - Show biblio records on OPAC result page + - XSLT path for the OPAC result page - pref: OPACXSLTResultsDisplay - choices: - yes: using XSLT stylesheets. - no: normally. + class: file - - - Show item details pages on the OPAC + - XSLT path for the details pages on the OPAC - pref: OPACXSLTDetailsDisplay - choices: - yes: using XSLT stylesheets. - no: normally. + class: file - - On pages displayed with XSLT stylesheets on the OPAC, - pref: DisplayOPACiconsXSLT diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/staff_client.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/staff_client.pref index df0a434..2e2e0f7 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/staff_client.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/staff_client.pref @@ -51,17 +51,13 @@ Staff Client: class: url - for the Staff Client's favicon. (This should be a complete URL, starting with http://.) - - - Show biblio records on result page in the staff client + - XSLT path for the result page in the staff client - pref: XSLTResultsDisplay - choices: - yes: using XSLT stylesheets. - no: normally. + class: file - - - Show item details pages in the staff client + - XSLT path for the details pages in the staff client - pref: XSLTDetailsDisplay - choices: - yes: using XSLT stylesheets. - no: normally. + class: file - - Use the Yahoo UI libraries - pref: yuipath diff --git a/opac/opac-detail.pl b/opac/opac-detail.pl index c4d8218..21d7b48 100755 --- a/opac/opac-detail.pl +++ b/opac/opac-detail.pl @@ -79,10 +79,9 @@ SetUTF8Flag($record); # XSLT processing of some stuff if (C4::Context->preference("OPACXSLTDetailsDisplay") ) { - $template->param( 'XSLTBloc' => XSLTParse4Display($biblionumber, $record, 'Detail', 'opac') ); + $template->param( 'XSLTBloc' => XSLTParse4Display($biblionumber, $record, C4::Context->preference("OPACXSLTDetailsDisplay") ) ); } - # We look for the busc param to build the simple paging from the search my $session = get_session($query->cookie("CGISESSID")); my %paging = (previous => {}, next => {}); -- 1.7.0.4 From stephane.delaune at biblibre.com Fri Feb 3 17:05:46 2012 From: stephane.delaune at biblibre.com (=?UTF-8?q?St=C3=A9phane=20Delaune?=) Date: Fri, 3 Feb 2012 17:05:46 +0100 Subject: [Koha-patches] [PATCH 3/3] Bug 6919/4032:followup to fix compatibility between 6919 and 4032 Message-ID: <1328285146-5960-1-git-send-email-stephane.delaune@biblibre.com> --- C4/Search.pm | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diff --git a/C4/Search.pm b/C4/Search.pm index 32f23c0..0096e69 100644 --- a/C4/Search.pm +++ b/C4/Search.pm @@ -1781,8 +1781,7 @@ sub searchResults { $debug && warn $marcrecord->as_formatted; my $interface = $search_context eq 'opac' ? 'OPAC' : ''; if (!$scan && C4::Context->preference($interface . "XSLTResultsDisplay")) { - $oldbiblio->{XSLTResultsRecord} = XSLTParse4Display($oldbiblio->{biblionumber}, $marcrecord, 'Results', - $search_context, 1); + $oldbiblio->{XSLTResultsRecord} = XSLTParse4Display($oldbiblio->{biblionumber}, $marcrecord, C4::Context->preference($interface . "XSLTResultsDisplay"), 1); # the last parameter tells Koha to clean up the problematic ampersand entities that Zebra outputs } -- 1.7.0.4 From christophe.croullebois at biblibre.com Sun Feb 5 20:15:47 2012 From: christophe.croullebois at biblibre.com (Christophe Croullebois) Date: Sun, 5 Feb 2012 20:15:47 +0100 Subject: [Koha-patches] [PATCH 1/1] Bug 7351 : feature that allows to delete a range of dates Message-ID: <1328469347-17498-1-git-send-email-christophe.croullebois@biblibre.com> Two new options, one for single holidays, the other for the repeatable holidays. Note that the exceptions are not deleted. --- C4/Calendar.pm | 70 ++++++++++++++++++++ .../prog/en/modules/tools/holidays.tt | 32 ++++++++-- tools/exceptionHolidays.pl | 54 ++++++++++++++- 3 files changed, 148 insertions(+), 8 deletions(-) diff --git a/C4/Calendar.pm b/C4/Calendar.pm index dc9037b..06a1a5a 100644 --- a/C4/Calendar.pm +++ b/C4/Calendar.pm @@ -45,6 +45,8 @@ BEGIN { &isHoliday &addDate &daysBetween + &delete_holiday_range + &delete_holiday_range_repeatable ); } @@ -529,6 +531,74 @@ sub delete_holiday { return $self; } +=head2 delete_holiday_range + + delete_holiday_range(weekday => $weekday + day => $day, + month => $month, + year => $year); + +Delete a holiday for $self->{branchcode}. + +C<$weekday> Is the week day to delete. + +C<$day> Is the day month to make the date to delete. + +C<$month> Is month to make the date to delete. + +C<$year> Is year to make the date to delete. + +=cut + +sub delete_holiday_range { + my $self = shift @_; + my %options = @_; + + my $dbh = C4::Context->dbh(); + my $isSingleHoliday = $dbh->prepare("SELECT id FROM special_holidays WHERE (branchcode = ?) AND (day = ?) AND (month = ?) AND (year = ?)"); + $isSingleHoliday->execute($self->{branchcode}, $options{day}, $options{month}, $options{year}); + if ($isSingleHoliday->rows) { + my $id = $isSingleHoliday->fetchrow; + $isSingleHoliday->finish; # Close the last query + my $deleteHoliday = $dbh->prepare("DELETE FROM special_holidays WHERE id = ?"); + $deleteHoliday->execute($id); + } +} + +=head2 delete_holiday_range_repeatable + + delete_holiday_range_repeatable(weekday => $weekday + day => $day, + month => $month, + year => $year); + +Delete a holiday for $self->{branchcode}. + +C<$weekday> Is the week day to delete. + +C<$day> Is the day month to make the date to delete. + +C<$month> Is month to make the date to delete. + +C<$year> Is year to make the date to delete. + +=cut + +sub delete_holiday_range_repeatable { + my $self = shift @_; + my %options = @_; + + my $dbh = C4::Context->dbh(); + my $isDayMonthHoliday = $dbh->prepare("SELECT id FROM repeatable_holidays WHERE (branchcode = ?) AND (day = ?) AND (month = ?)"); + $isDayMonthHoliday->execute($self->{branchcode}, $options{day}, $options{month}); + if ($isDayMonthHoliday->rows) { + my $id = $isDayMonthHoliday->fetchrow; + $isDayMonthHoliday->finish; + my $deleteHoliday = $dbh->prepare("DELETE FROM repeatable_holidays WHERE (id = ?)"); + $deleteHoliday->execute($id); + } +} + =head2 isHoliday $isHoliday = isHoliday($day, $month $year); diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/holidays.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/holidays.tt index 686e3af..6042cae 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/holidays.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/holidays.tt @@ -83,8 +83,8 @@ function Help() { newin=window.open("/cgi-bin/koha/help.pl","KohaHelp",'width=600,height=600,toolbar=false,scrollbars=yes'); } - $(document).ready(function() { + $(document).ready(function() { [% IF ( dateformat_metric ) %] $.tablesorter.addParser({ // http://tablesorter.com/docs/example-parsers.html id: 'shortDates', is: function(s){ @@ -129,6 +129,7 @@ $(this).parent().find(".hint").toggle(); return false; }); $("#dateofrange").each(function () { this.value = "" }); + $("#datecancelrange").each(function () { this.value = "" }); }); //]]> @@ -185,7 +186,7 @@
  • - Date: + From Date: , [% IF ( dateformat_us ) %]//[% ELSIF ( dateformat_metric ) %]//[% ELSE %]//[% END %] @@ -196,6 +197,20 @@
  • +
  • + To Date : + + Show Calendar + +
  • @@ -209,10 +224,17 @@
  • [?]
    This will delete this holiday rule. If it is a repeatable holiday, this option checks for posible exceptions. If an exception exists, this option will remove the exception and set the date to a regular holiday.
  • +
  • . + [?] +
    This will delete the single holidays rules only. The repeatable holidays and exceptions will not be deleted
    +
  • +
  • . + [?] +
    This will delete the repeated holidays rules only. The repeatable holidays will be deleted but not exceptions
    +
  • - [?] -
    This will save changes to the holiday's title and description. If the information for a repeatable holiday is modified, it affects all of the dates on which the holiday is repeated.
  • - + [?] +
    This will save changes to the holiday's title and description. If the information for a repeatable holiday is modified, it affects all of the dates on which the holiday is repeated.
    diff --git a/tools/exceptionHolidays.pl b/tools/exceptionHolidays.pl index 64a4860..7d94eed 100755 --- a/tools/exceptionHolidays.pl +++ b/tools/exceptionHolidays.pl @@ -7,7 +7,7 @@ use CGI; use C4::Auth; use C4::Output; - +use DateTime; use C4::Calendar; @@ -19,10 +19,13 @@ my $weekday = $input->param('showWeekday'); my $day = $input->param('showDay'); my $month = $input->param('showMonth'); my $year = $input->param('showYear'); +my $day1; +my $month1; +my $year1; my $title = $input->param('showTitle'); my $description = $input->param('showDescription'); my $holidaytype = $input->param('showHolidayType'); - +my $datecancelrange = $input->param('datecancelrange'); my $calendardate = sprintf("%04d-%02d-%02d", $year, $month, $day); my $isodate = C4::Dates->new($calendardate, 'iso'); $calendardate = $isodate->output('syspref'); @@ -36,7 +39,20 @@ if ($description) { } else { $description = ''; } - +my @dateend = split(/[\/-]/, $datecancelrange); +if (C4::Context->preference("dateformat") eq "metric") { + $day1 = $dateend[0]; + $month1 = $dateend[1]; + $year1 = $dateend[2]; +}elsif (C4::Context->preference("dateformat") eq "us") { + $month1 = $dateend[0]; + $day1 = $dateend[1]; + $year1 = $dateend[2]; +} else { + $year1 = $dateend[0]; + $month1 = $dateend[1]; + $day1 = $dateend[2]; +} if ($input->param('showOperation') eq 'exception') { $calendar->insert_exception_holiday(day => $day, month => $month, @@ -71,5 +87,37 @@ if ($input->param('showOperation') eq 'exception') { day => $day, month => $month, year => $year); +}elsif ($input->param('showOperation') eq 'deleterange') { + if ($year1 && $month1 && $day1){ + #Make an array with holiday's days + my $first_dt = DateTime->new(year => $year, month => $month, day => $day); + my $end_dt = DateTime->new(year => $year1, month => $month1, day => $day1); + my @holiday_list = (); + for (my $dt = $first_dt->clone(); $dt <= $end_dt; $dt->add(days => 1) ){ + push @holiday_list, $dt->clone(); + } + foreach my $date (@holiday_list){ + $calendar->delete_holiday_range(weekday => $weekday, + day => $date->{local_c}->{day}, + month => $date->{local_c}->{month}, + year => $date->{local_c}->{year}); + } + } +}elsif ($input->param('showOperation') eq 'deleterangerepeat') { + if ($year1 && $month1 && $day1){ + #Make an array with holiday's days + my $first_dt = DateTime->new(year => $year, month => $month, day => $day); + my $end_dt = DateTime->new(year => $year1, month => $month1, day => $day1); + my @holiday_list = (); + for (my $dt = $first_dt->clone(); $dt <= $end_dt; $dt->add(days => 1) ){ + push @holiday_list, $dt->clone(); + } + foreach my $date (@holiday_list){ + $calendar->delete_holiday_range_repeatable(weekday => $weekday, + day => $date->{local_c}->{day}, + month => $date->{local_c}->{month}); + } + } } + print $input->redirect("/cgi-bin/koha/tools/holidays.pl?branch=$branchcode&calendardate=$calendardate"); -- 1.7.5.4 From srdjan at catalyst.net.nz Mon Feb 6 01:35:43 2012 From: srdjan at catalyst.net.nz (Srdjan Jankovic) Date: Mon, 6 Feb 2012 13:35:43 +1300 Subject: [Koha-patches] [PATCH] bug_7458: A call number plugin In-Reply-To: References: Message-ID: <1328488543-23036-1-git-send-email-srdjan@catalyst.net.nz> --- cataloguing/value_builder/callnumber-KU.pl | 135 ++++++++++++++++++++++++++++ installer/data/mysql/kohastructure.sql | 1 + installer/data/mysql/updatedatabase.pl | 8 ++ 3 files changed, 144 insertions(+), 0 deletions(-) create mode 100755 cataloguing/value_builder/callnumber-KU.pl diff --git a/cataloguing/value_builder/callnumber-KU.pl b/cataloguing/value_builder/callnumber-KU.pl new file mode 100755 index 0000000..8c4b1b7 --- /dev/null +++ b/cataloguing/value_builder/callnumber-KU.pl @@ -0,0 +1,135 @@ +#!/usr/bin/perl + +# Copyright 2012 CatalystIT Ltd +# +# 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use strict; +use warnings; +use C4::Auth; +use CGI; +use C4::Context; + +=head1 DESCRIPTION + +Is used for callnumber computation. + +User must supply a letter prefix (unspecified length) followed by an empty space followed by a "number". +"Number" is 4 character long, and is either a number sequence which is 01 padded. +If input does not conform with this format any processing is omitted. + +Some examples of legal values that trigger auto allocation: + +AAA 0 - returns first unused number AAA 0xxx starting with AAA 0001 +BBB 12 - returns first unused number BBB 12xx starting with BBB 1201 +CCC QW - returns first unused number CCC QWxx starting with CCC QW01 + +=cut + +sub plugin_parameters { +} + +sub plugin_javascript { + my ($dbh,$record,$tagslib,$field_number,$tabloop) = @_; + my $res=" + + "; + + return ($field_number,$res); +} + +my $BASE_CALLNUMBER_RE = qr/^(\w+) (\w+)$/; +sub plugin { + my ($input) = @_; + my $code = $input->param('code'); + + my ($template, $loggedinuser, $cookie) = get_template_and_user({ + template_name => "cataloguing/value_builder/ajax.tmpl", + query => $input, + type => "intranet", + authnotrequired => 0, + flagsrequired => {editcatalogue => '*'}, + debug => 1, + }); + + my $ret; + my ($alpha, $num) = ($code =~ $BASE_CALLNUMBER_RE); + if (defined $num) { # otherwise no point + my ($num_alpha, $num_num) = ($num =~ m/^(\D+)?(\d+)?$/); + $num_alpha ||= ''; + my $pad_len = 4 - length($num); + + if ($pad_len > 0) { + my $num_padded = $num_num; + $num_padded .= "0" x ($pad_len - 1) if $pad_len > 1; + $num_padded .= "1"; + my $padded = "$alpha $num_alpha" . $num_padded; + + my $dbh = C4::Context->dbh; + if ( my $first = $dbh->selectrow_array("SELECT itemcallnumber + FROM items + WHERE itemcallnumber = ?", undef, $padded) ) { + my $icn = $dbh->selectcol_arrayref("SELECT itemcallnumber + FROM items + WHERE itemcallnumber LIKE ? + AND itemcallnumber > ? + ORDER BY itemcallnumber", undef, "$alpha $num_alpha%", $first); + my $next = $num_padded + 1; + my $len = length($num_padded); + foreach (@$icn) { + my ($num1) = ( m/(\d+)$/o ); + if ($num1 > $next) { # a hole in numbering found, stop + last; + } + $next++; + } + $ret = "$alpha $num_alpha" . sprintf("%0${len}d", $next) if length($next) <= $len; # no overflow + } + else { + $ret = $padded; + } + } + } + + $template->param( + return => $ret || $code + ); + output_html_with_http_headers $input, $cookie, $template->output; +} + +1; diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql index 37113c2..34bf1d6 100644 --- a/installer/data/mysql/kohastructure.sql +++ b/installer/data/mysql/kohastructure.sql @@ -1045,6 +1045,7 @@ CREATE TABLE `items` ( -- holdings/item information KEY `itembibnoidx` (`biblionumber`), KEY `homebranch` (`homebranch`), KEY `holdingbranch` (`holdingbranch`), + KEY (itemcallnumber), CONSTRAINT `items_ibfk_1` FOREIGN KEY (`biblioitemnumber`) REFERENCES `biblioitems` (`biblioitemnumber`) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT `items_ibfk_2` FOREIGN KEY (`homebranch`) REFERENCES `branches` (`branchcode`) ON UPDATE CASCADE, CONSTRAINT `items_ibfk_3` FOREIGN KEY (`holdingbranch`) REFERENCES `branches` (`branchcode`) ON UPDATE CASCADE diff --git a/installer/data/mysql/updatedatabase.pl b/installer/data/mysql/updatedatabase.pl index 099dfb9..b6f72f9 100755 --- a/installer/data/mysql/updatedatabase.pl +++ b/installer/data/mysql/updatedatabase.pl @@ -4663,6 +4663,14 @@ ENDOFRENEWAL print "Upgrade to $DBversion done (Added a system preference to allow renewal of Patron account either from todays date or from existing expiry date in the patrons account.)\n"; SetVersion($DBversion); } + +$DBversion = "3.07.00.XXX"; +if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) { + $dbh->do("ALTER TABLE items ADD KEY (itemcallnumber)"); + print "Upgrade to $DBversion done (Added index on items.itemcallnumber)\n"; + SetVersion($DBversion); +} + =head1 FUNCTIONS =head2 DropAllForeignKeys($table) -- 1.6.5 From stephane.delaune at biblibre.com Mon Feb 6 12:20:12 2012 From: stephane.delaune at biblibre.com (=?UTF-8?q?St=C3=A9phane=20Delaune?=) Date: Mon, 6 Feb 2012 12:20:12 +0100 Subject: [Koha-patches] [PATCH 1/2] Bug 7246 add offset/length and where options to rebuild_zebra Message-ID: <1328527213-5174-1-git-send-email-stephane.delaune@biblibre.com> From: Paul Poulain This patch reimplement a feature that is on biblibre/master for Koha-community/master It adds 4 parameters: * offset = the offset of record. Say 1000 to start rebuilding at the 1000th record of your database * length = how many records to export. Say 400 to export only 400 records * where = add a where clause to rebuild only a given itemtype, or anything you want to filter on * l = how many items should be export with biblios. This is a usefull option when you have records with so many items that they can result in a record higher than 99999bytes, that zebra don't like at all Another improvement resulting from offset & length limit is the rebuild_zebra_sliced.zsh that will be submitted in another patch. rebuild_zebra_sliced will slice your all database in small chunks, and, if something went wrong for a given slice, will slice the slice, and repeat, until you reach a slice size of 1, showing which record is wrong in your database. --- misc/migration_tools/rebuild_zebra.pl | 33 +++++++++++++++++++++++++++++---- 1 files changed, 29 insertions(+), 4 deletions(-) diff --git a/misc/migration_tools/rebuild_zebra.pl b/misc/migration_tools/rebuild_zebra.pl index 31e8125..94b37b8 100755 --- a/misc/migration_tools/rebuild_zebra.pl +++ b/misc/migration_tools/rebuild_zebra.pl @@ -34,6 +34,10 @@ my $want_help; my $as_xml; my $process_zebraqueue; my $do_not_clear_zebraqueue; +my $item_limit; +my $length; +my $where; +my $offset; my $verbose_logging = 0; my $zebraidx_log_opt = " -v none,fatal,warn "; my $result = GetOptions( @@ -51,7 +55,11 @@ my $result = GetOptions( 'x' => \$as_xml, 'y' => \$do_not_clear_zebraqueue, 'z' => \$process_zebraqueue, - 'v+' => \$verbose_logging, + 'l:i' => \$item_limit, + 'where:s' => \$where, + 'length:i' => \$length, + 'offset:i' => \$offset, + 'v+' => \$verbose_logging, ); @@ -294,13 +302,21 @@ sub select_all_records { } sub select_all_authorities { - my $sth = $dbh->prepare("SELECT authid FROM auth_header"); + my $strsth=qq{SELECT authid FROM auth_header}; + $strsth.=qq{ WHERE $where } if ($where); + $strsth.=qq{ LIMIT $length } if ($length && !$offset); + $strsth.=qq{ LIMIT $offset,$length } if ($length && $offset); + my $sth = $dbh->prepare($strsth); $sth->execute(); return $sth; } sub select_all_biblios { - my $sth = $dbh->prepare("SELECT biblionumber FROM biblioitems ORDER BY biblionumber"); + my $strsth = qq{ SELECT biblionumber FROM biblioitems }; + $strsth.=qq{ WHERE $where } if ($where); + $strsth.=qq{ LIMIT $length } if ($length && !$offset); + $strsth.=qq{ LIMIT $offset,$length } if ($offset); + my $sth = $dbh->prepare($strsth); $sth->execute(); return $sth; } @@ -635,11 +651,20 @@ Parameters: the same records - specify -y to override this. Cannot be used with -z. + -l set a maximum number of exported items per biblio. + Doesn't work with -nosanitize. -v increase the amount of logging. Normally only warnings and errors from the indexing are shown. Use log level 2 (-v -v) to include all Zebra logs. - -munge-config Deprecated option to try + --length 1234 how many biblio you want to export + --offset 1243 offset you want to start to + example: --offset 500 --length=500 will result in a LIMIT 500,1000 (exporting 1000 records, starting by the 500th one) + note that the numbers are NOT related to biblionumber, that's the intended behaviour. + --where let you specify a WHERE query, like itemtype='BOOK' + or something like that + + --munge-config Deprecated option to try to fix Zebra config files. --help or -h show this message. _USAGE_ -- 1.7.0.4 From stephane.delaune at biblibre.com Mon Feb 6 12:20:13 2012 From: stephane.delaune at biblibre.com (=?UTF-8?q?St=C3=A9phane=20Delaune?=) Date: Mon, 6 Feb 2012 12:20:13 +0100 Subject: [Koha-patches] [PATCH 2/2] Bug 7286: fix rebuild_zebra.pl to add rebuild_zebra_sliced.zsh In-Reply-To: <1328527213-5174-1-git-send-email-stephane.delaune@biblibre.com> References: <1328527213-5174-1-git-send-email-stephane.delaune@biblibre.com> Message-ID: <1328527213-5174-2-git-send-email-stephane.delaune@biblibre.com> --- misc/migration_tools/rebuild_zebra.pl | 23 +++++- misc/migration_tools/rebuild_zebra_sliced.zsh | 127 +++++++++++++++++++++++++ 2 files changed, 149 insertions(+), 1 deletions(-) create mode 100755 misc/migration_tools/rebuild_zebra_sliced.zsh diff --git a/misc/migration_tools/rebuild_zebra.pl b/misc/migration_tools/rebuild_zebra.pl index 94b37b8..ebc2c41 100755 --- a/misc/migration_tools/rebuild_zebra.pl +++ b/misc/migration_tools/rebuild_zebra.pl @@ -86,6 +86,12 @@ if ( !$as_xml and $nosanitize ) { die $msg; } +if ( $nosanitize and $item_limit ) { + my $msg = "Cannot specify both -item_limit and -nosanitize\n"; + $msg .= "Please do '$0 --help' to see usage.\n"; + die $msg; +} + if ($process_zebraqueue and ($skip_export or $reset)) { my $msg = "Cannot specify -r or -s if -z is specified\n"; $msg .= "Please do '$0 --help' to see usage.\n"; @@ -422,6 +428,7 @@ sub generate_deleted_marc_records { my $marc = MARC::Record->new(); if ($record_type eq 'biblio') { fix_biblio_ids($marc, $record_number, $record_number); + fix_biblio_items( $marc ) if $item_limit; } else { fix_authority_id($marc, $record_number); } @@ -447,7 +454,11 @@ sub get_corrected_marc_record { if (defined $marc) { fix_leader($marc); - if ($record_type eq 'authority') { + if ( $record_type eq 'biblio' ) { + my $succeeded = fix_biblio_ids( $marc, $record_number ); + fix_biblio_items( $marc ) if $item_limit; + return unless $succeeded; + } else { fix_authority_id($marc, $record_number); } if (C4::Context->preference("marcflavour") eq "UNIMARC") { @@ -514,6 +525,16 @@ sub fix_leader { $marc->leader(substr($leader, 0, 24)); } +sub fix_biblio_items { + my $marc = shift; + my ($itemtagfield, $itemtagsubfield) = GetMarcFromKohaField('items.itemnumber',''); + my $i = 0; + for my $itemfield ( $marc->field($itemtagfield) ) { + $marc->delete_field($itemfield) if $i >= $item_limit; + $i++; + } +} + sub fix_biblio_ids { # FIXME - it is essential to ensure that the biblionumber is present, # otherwise, Zebra will choke on the record. However, this diff --git a/misc/migration_tools/rebuild_zebra_sliced.zsh b/misc/migration_tools/rebuild_zebra_sliced.zsh new file mode 100755 index 0000000..e418fd0 --- /dev/null +++ b/misc/migration_tools/rebuild_zebra_sliced.zsh @@ -0,0 +1,127 @@ +#!/usr/bin/zsh + +# Copyright 2011 BibLibre SARL +# 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +INCREMENT=$1 +BIBLIOSTART=$2 +BIBLIOEND=$3 + +#echo " | $INCREMENT , $BIBLIOSTART , $BIBLIOEND | "; +# this script rebuild the zebra index recursively +# BIBLIOSTART is the record number to BIBLIOSTART on +# BIBLIOEND is the record number to BIBLIOEND on +# increment specify how many records we must try at once +# At the BIBLIOEND of each "chunk", this script checks if the indexing process has been OK +# if it hasn't, the slice is splitted in 10, and the reindexing is called again on each smaller chunk +# if the increment goes to 1, it means we tried to reindex 1 by 1, and the failing indexing concern wrong records + +# the logs are stored in a directory called logs/ that must be a subdirectory of reindex.zsh + +# at the BIBLIOEND of the script, just type : +#grep -l "previous transaction" `ls rebuild1.*.err` +# the result contains all the biblios that have not been indexed +# WARNING : the numbers are not the biblionumber but the record number, they can be reached by : +# SELECT biblionumber FROM biblio LIMIT YourNumberHere,1; + +# EXAMPLE to run the script on a 800 000 biblios database : +# ./reindex.zsh 50000 0 800000 +# will reindex the DB, BIBLIOSTARTing with chunks of 50k biblios +#if { grep -E "previous transaction" `dirname $0`/logs/rebuild$INCREMENT.$i.err } ; then + +lastbiblionumber=`perl -e '#!/usr/bin/perl +use C4::Context; +my $dbh = C4::Context->dbh; +my $querylastbiblionumber = "SELECT max(biblionumber) FROM biblio;"; +my $sthlastbiblionumber = $dbh->prepare($querylastbiblionumber); +$sthlastbiblionumber->execute(); +my ( $lastbiblionumber ) = $sthlastbiblionumber->fetchrow_array; print $lastbiblionumber;'` +#echo $lastbiblionumber; +let "maxbiblionumber = $lastbiblionumber + 1" +if [ $# = 2 ] +then + BIBLIOEND=$lastbiblionumber +elif [ $# = 1 ] +then + BIBLIOSTART=0 + BIBLIOEND=$lastbiblionumber +elif [ $# = 0 ] +then + INCREMENT=10000 + BIBLIOSTART=0 + BIBLIOEND=$lastbiblionumber +fi +if [[ $INCREMENT =~ ^10*$ ]] +then +else + echo "The first argument (INCREMENT) must be 1 or a multiple of 10" + exit 2 +fi +if [[ $BIBLIOSTART =~ ^[0-9]*$ ]] +then +else + echo "The second argument (BIBLIOSTART) must be an integer" + exit 2 +fi +if [[ $BIBLIOEND =~ ^[0-9]*$ ]] +then +else + echo "The third argument (BIBLIOEND) must be an integer" + exit 2 +fi +if [ $BIBLIOSTART -lt $BIBLIOEND ] +then +else + echo "The second argument (BIBLIOSTART) must be lower than the third argument (BIBLIOEND)" + exit 2 +fi +if [ $BIBLIOEND -lt $maxbiblionumber ] +then +else + echo "end" + exit 1 +fi + ls `dirname $0`/logs/ >/dev/null 2>&1 + if [ $? != 0 ] + then + mkdir `dirname $0`/logs + else + rm `dirname $0`/logs/* + fi + #/home/koha/src/misc/migration_tools/rebuild_zebra.pl -r -b -v -x -nosanitize -offset 1 -length 1 + for ((i=$BIBLIOSTART ; i<$BIBLIOEND ; i=i+$INCREMENT)) + do + echo "I = " $i "with increment " $INCREMENT + `dirname $0`/rebuild_zebra.pl -b -v -x -nosanitize -d /tmp/rebuild -k -offset $INCREMENT -length $i > `dirname $0`/logs/rebuild$INCREMENT.$i.log 2> `dirname $0`/logs/rebuild$INCREMENT.$i.err + if (($INCREMENT >1 )); + then + if { grep -q "previous transaction" `dirname $0`/logs/rebuild$INCREMENT.$i.err } ; + then + echo "I must split $i (increment $INCREMENT) because previous transaction didn't reach commit" + ((subincrement=$INCREMENT/10)) + ((newBIBLIOEND=$i+$INCREMENT)) + $0 $subincrement $i $newBIBLIOEND + elif { ! grep -q "Records: $INCREMENT" `dirname $0`/logs/rebuild$INCREMENT.$i.err } ; + then + echo "I must split $i (increment $INCREMENT) because index was uncomplete, less than $INCREMENT records indexed" + ((subincrement=$INCREMENT/10)) + ((newBIBLIOEND=$i+$INCREMENT)) + $0 $subincrement $i $newBIBLIOEND + fi + fi + done +exit 0 -- 1.7.0.4 From stephane.delaune at biblibre.com Mon Feb 6 14:03:26 2012 From: stephane.delaune at biblibre.com (=?UTF-8?q?St=C3=A9phane=20Delaune?=) Date: Mon, 6 Feb 2012 14:03:26 +0100 Subject: [Koha-patches] [PATCH 1/2] Bug 7246 add offset/length and where options to rebuild_zebra Message-ID: <1328533407-7575-1-git-send-email-stephane.delaune@biblibre.com> From: Paul Poulain This patch reimplement a feature that is on biblibre/master for Koha-community/master It adds 4 parameters: * offset = the offset of record. Say 1000 to start rebuilding at the 1000th record of your database * length = how many records to export. Say 400 to export only 400 records * where = add a where clause to rebuild only a given itemtype, or anything you want to filter on * l = how many items should be export with biblios. This is a usefull option when you have records with so many items that they can result in a record higher than 99999bytes, that zebra don't like at all Another improvement resulting from offset & length limit is the rebuild_zebra_sliced.zsh that will be submitted in another patch. rebuild_zebra_sliced will slice your all database in small chunks, and, if something went wrong for a given slice, will slice the slice, and repeat, until you reach a slice size of 1, showing which record is wrong in your database. --- misc/migration_tools/rebuild_zebra.pl | 33 +++++++++++++++++++++++++++++---- 1 files changed, 29 insertions(+), 4 deletions(-) diff --git a/misc/migration_tools/rebuild_zebra.pl b/misc/migration_tools/rebuild_zebra.pl index 31e8125..94b37b8 100755 --- a/misc/migration_tools/rebuild_zebra.pl +++ b/misc/migration_tools/rebuild_zebra.pl @@ -34,6 +34,10 @@ my $want_help; my $as_xml; my $process_zebraqueue; my $do_not_clear_zebraqueue; +my $item_limit; +my $length; +my $where; +my $offset; my $verbose_logging = 0; my $zebraidx_log_opt = " -v none,fatal,warn "; my $result = GetOptions( @@ -51,7 +55,11 @@ my $result = GetOptions( 'x' => \$as_xml, 'y' => \$do_not_clear_zebraqueue, 'z' => \$process_zebraqueue, - 'v+' => \$verbose_logging, + 'l:i' => \$item_limit, + 'where:s' => \$where, + 'length:i' => \$length, + 'offset:i' => \$offset, + 'v+' => \$verbose_logging, ); @@ -294,13 +302,21 @@ sub select_all_records { } sub select_all_authorities { - my $sth = $dbh->prepare("SELECT authid FROM auth_header"); + my $strsth=qq{SELECT authid FROM auth_header}; + $strsth.=qq{ WHERE $where } if ($where); + $strsth.=qq{ LIMIT $length } if ($length && !$offset); + $strsth.=qq{ LIMIT $offset,$length } if ($length && $offset); + my $sth = $dbh->prepare($strsth); $sth->execute(); return $sth; } sub select_all_biblios { - my $sth = $dbh->prepare("SELECT biblionumber FROM biblioitems ORDER BY biblionumber"); + my $strsth = qq{ SELECT biblionumber FROM biblioitems }; + $strsth.=qq{ WHERE $where } if ($where); + $strsth.=qq{ LIMIT $length } if ($length && !$offset); + $strsth.=qq{ LIMIT $offset,$length } if ($offset); + my $sth = $dbh->prepare($strsth); $sth->execute(); return $sth; } @@ -635,11 +651,20 @@ Parameters: the same records - specify -y to override this. Cannot be used with -z. + -l set a maximum number of exported items per biblio. + Doesn't work with -nosanitize. -v increase the amount of logging. Normally only warnings and errors from the indexing are shown. Use log level 2 (-v -v) to include all Zebra logs. - -munge-config Deprecated option to try + --length 1234 how many biblio you want to export + --offset 1243 offset you want to start to + example: --offset 500 --length=500 will result in a LIMIT 500,1000 (exporting 1000 records, starting by the 500th one) + note that the numbers are NOT related to biblionumber, that's the intended behaviour. + --where let you specify a WHERE query, like itemtype='BOOK' + or something like that + + --munge-config Deprecated option to try to fix Zebra config files. --help or -h show this message. _USAGE_ -- 1.7.0.4 From stephane.delaune at biblibre.com Mon Feb 6 14:03:27 2012 From: stephane.delaune at biblibre.com (=?UTF-8?q?St=C3=A9phane=20Delaune?=) Date: Mon, 6 Feb 2012 14:03:27 +0100 Subject: [Koha-patches] [PATCH 2/2] Bug 7286: fix rebuild_zebra.pl to add rebuild_zebra_sliced.zsh In-Reply-To: <1328533407-7575-1-git-send-email-stephane.delaune@biblibre.com> References: <1328533407-7575-1-git-send-email-stephane.delaune@biblibre.com> Message-ID: <1328533407-7575-2-git-send-email-stephane.delaune@biblibre.com> --- misc/migration_tools/rebuild_zebra.pl | 23 +++++- misc/migration_tools/rebuild_zebra_sliced.zsh | 127 +++++++++++++++++++++++++ 2 files changed, 149 insertions(+), 1 deletions(-) create mode 100755 misc/migration_tools/rebuild_zebra_sliced.zsh diff --git a/misc/migration_tools/rebuild_zebra.pl b/misc/migration_tools/rebuild_zebra.pl index 94b37b8..ebc2c41 100755 --- a/misc/migration_tools/rebuild_zebra.pl +++ b/misc/migration_tools/rebuild_zebra.pl @@ -86,6 +86,12 @@ if ( !$as_xml and $nosanitize ) { die $msg; } +if ( $nosanitize and $item_limit ) { + my $msg = "Cannot specify both -item_limit and -nosanitize\n"; + $msg .= "Please do '$0 --help' to see usage.\n"; + die $msg; +} + if ($process_zebraqueue and ($skip_export or $reset)) { my $msg = "Cannot specify -r or -s if -z is specified\n"; $msg .= "Please do '$0 --help' to see usage.\n"; @@ -422,6 +428,7 @@ sub generate_deleted_marc_records { my $marc = MARC::Record->new(); if ($record_type eq 'biblio') { fix_biblio_ids($marc, $record_number, $record_number); + fix_biblio_items( $marc ) if $item_limit; } else { fix_authority_id($marc, $record_number); } @@ -447,7 +454,11 @@ sub get_corrected_marc_record { if (defined $marc) { fix_leader($marc); - if ($record_type eq 'authority') { + if ( $record_type eq 'biblio' ) { + my $succeeded = fix_biblio_ids( $marc, $record_number ); + fix_biblio_items( $marc ) if $item_limit; + return unless $succeeded; + } else { fix_authority_id($marc, $record_number); } if (C4::Context->preference("marcflavour") eq "UNIMARC") { @@ -514,6 +525,16 @@ sub fix_leader { $marc->leader(substr($leader, 0, 24)); } +sub fix_biblio_items { + my $marc = shift; + my ($itemtagfield, $itemtagsubfield) = GetMarcFromKohaField('items.itemnumber',''); + my $i = 0; + for my $itemfield ( $marc->field($itemtagfield) ) { + $marc->delete_field($itemfield) if $i >= $item_limit; + $i++; + } +} + sub fix_biblio_ids { # FIXME - it is essential to ensure that the biblionumber is present, # otherwise, Zebra will choke on the record. However, this diff --git a/misc/migration_tools/rebuild_zebra_sliced.zsh b/misc/migration_tools/rebuild_zebra_sliced.zsh new file mode 100755 index 0000000..b6af48c --- /dev/null +++ b/misc/migration_tools/rebuild_zebra_sliced.zsh @@ -0,0 +1,127 @@ +#!/usr/bin/zsh + +# Copyright 2011 BibLibre SARL +# 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +INCREMENT=$1 +BIBLIOSTART=$2 +BIBLIOEND=$3 + +#echo " | $INCREMENT , $BIBLIOSTART , $BIBLIOEND | "; +# this script rebuild the zebra index recursively +# BIBLIOSTART is the record number to BIBLIOSTART on +# BIBLIOEND is the record number to BIBLIOEND on +# increment specify how many records we must try at once +# At the BIBLIOEND of each "chunk", this script checks if the indexing process has been OK +# if it hasn't, the slice is splitted in 10, and the reindexing is called again on each smaller chunk +# if the increment goes to 1, it means we tried to reindex 1 by 1, and the failing indexing concern wrong records + +# the logs are stored in a directory called logs/ that must be a subdirectory of reindex.zsh + +# at the BIBLIOEND of the script, just type : +#grep -l "previous transaction" `ls rebuild1.*.err` +# the result contains all the biblios that have not been indexed +# WARNING : the numbers are not the biblionumber but the record number, they can be reached by : +# SELECT biblionumber FROM biblio LIMIT YourNumberHere,1; + +# EXAMPLE to run the script on a 800 000 biblios database : +# ./reindex.zsh 50000 0 800000 +# will reindex the DB, BIBLIOSTARTing with chunks of 50k biblios +#if { grep -E "previous transaction" `dirname $0`/logs/rebuild$INCREMENT.$i.err } ; then + +lastbiblionumber=`perl -e '#!/usr/bin/perl +use C4::Context; +my $dbh = C4::Context->dbh; +my $querylastbiblionumber = "SELECT max(biblionumber) FROM biblio;"; +my $sthlastbiblionumber = $dbh->prepare($querylastbiblionumber); +$sthlastbiblionumber->execute(); +my ( $lastbiblionumber ) = $sthlastbiblionumber->fetchrow_array; print $lastbiblionumber;'` +#echo $lastbiblionumber; +let "maxbiblionumber = $lastbiblionumber + 1" +if [ $# = 2 ] +then + BIBLIOEND=$lastbiblionumber +elif [ $# = 1 ] +then + BIBLIOSTART=0 + BIBLIOEND=$lastbiblionumber +elif [ $# = 0 ] +then + INCREMENT=10000 + BIBLIOSTART=0 + BIBLIOEND=$lastbiblionumber +fi +if [[ $INCREMENT =~ ^10*$ ]] +then +else + echo "The first argument (INCREMENT) must be 1 or a multiple of 10" + exit 2 +fi +if [[ $BIBLIOSTART =~ ^[0-9]*$ ]] +then +else + echo "The second argument (BIBLIOSTART) must be an integer" + exit 2 +fi +if [[ $BIBLIOEND =~ ^[0-9]*$ ]] +then +else + echo "The third argument (BIBLIOEND) must be an integer" + exit 2 +fi +if [ $BIBLIOSTART -lt $BIBLIOEND ] +then +else + echo "The second argument (BIBLIOSTART) must be lower than the third argument (BIBLIOEND)" + exit 2 +fi +if [ $BIBLIOEND -lt $maxbiblionumber ] +then +else + echo "end" + exit 1 +fi + ls `dirname $0`/logs/ >/dev/null 2>&1 + if [ $? != 0 ] + then + mkdir `dirname $0`/logs + else + rm `dirname $0`/logs/* + fi + #/home/koha/src/misc/migration_tools/rebuild_zebra.pl -r -b -v -x -nosanitize -length 1 -offset 1 + for ((i=$BIBLIOSTART ; i<$BIBLIOEND ; i=i+$INCREMENT)) + do + echo "I = " $i "with increment " $INCREMENT + `dirname $0`/rebuild_zebra.pl -b -v -x -nosanitize -d /tmp/rebuild -k -length $INCREMENT -offset $i > `dirname $0`/logs/rebuild$INCREMENT.$i.log 2> `dirname $0`/logs/rebuild$INCREMENT.$i.err + if (($INCREMENT >1 )); + then + if { grep -q "previous transaction" `dirname $0`/logs/rebuild$INCREMENT.$i.err } ; + then + echo "I must split $i (increment $INCREMENT) because previous transaction didn't reach commit" + ((subincrement=$INCREMENT/10)) + ((newBIBLIOEND=$i+$INCREMENT)) + $0 $subincrement $i $newBIBLIOEND + elif { ! grep -q "Records: $INCREMENT" `dirname $0`/logs/rebuild$INCREMENT.$i.err } ; + then + echo "I must split $i (increment $INCREMENT) because index was uncomplete, less than $INCREMENT records indexed" + ((subincrement=$INCREMENT/10)) + ((newBIBLIOEND=$i+$INCREMENT)) + $0 $subincrement $i $newBIBLIOEND + fi + fi + done +exit 0 -- 1.7.0.4 From januszop at gmail.com Mon Feb 6 16:20:38 2012 From: januszop at gmail.com (Janusz Kaczmarek) Date: Mon, 6 Feb 2012 16:20:38 +0100 Subject: [Koha-patches] [PATCH] Bug 7502: Error in records.abs for marc21/biblios Message-ID: <1328541638-31231-1-git-send-email-januszop@gmail.com> There is an error in records.abs in marc21/biblios causing a zebra warning: 15:51:13-06/02 zebraidx(3276) [warn] Unknown register type: Subject --- etc/zebradb/marc_defs/marc21/biblios/record.abs | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/etc/zebradb/marc_defs/marc21/biblios/record.abs b/etc/zebradb/marc_defs/marc21/biblios/record.abs index 6983230..b61903f 100644 --- a/etc/zebradb/marc_defs/marc21/biblios/record.abs +++ b/etc/zebradb/marc_defs/marc21/biblios/record.abs @@ -170,7 +170,7 @@ melm 611$a Name-and-title,Subject,Subject:p melm 611$t Name-and-title,Title,Subject,Subject:p melm 611$9 Koha-Auth-Number melm 611 Conference-name,Name,Subject,Subject:p -melm 630$n Thematic-number,Subject:Subject:p +melm 630$n Thematic-number,Subject,Subject:p melm 630$r Music-key,Subject,Subject:p melm 630$9 Koha-Auth-Number melm 630 Subject,Subject:p -- 1.7.2.5 From adrien.saurat at biblibre.com Mon Feb 6 17:09:37 2012 From: adrien.saurat at biblibre.com (Adrien Saurat) Date: Mon, 6 Feb 2012 17:09:37 +0100 Subject: [Koha-patches] [PATCH] [SIGNED-OFF] Bug 6985 - remove kw, wrdl from the search results Message-ID: <1328544577-8050-1-git-send-email-adrien.saurat@biblibre.com> From: Liz Rea To test: * Apply patch * Do a search in the OPAC, the result page should now say "Your search returned X results" instead of "Your search for "kw,wrdl:yyy" returned x results" * Do a search that will have no results, kw,wrdl should not appear in the text. Signed-off-by: Jared Camins-Esakov Signed-off-by: Adrien Saurat --- koha-tmpl/opac-tmpl/prog/en/includes/masthead.inc | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/koha-tmpl/opac-tmpl/prog/en/includes/masthead.inc b/koha-tmpl/opac-tmpl/prog/en/includes/masthead.inc index 0ffb881..eb36f6f 100644 --- a/koha-tmpl/opac-tmpl/prog/en/includes/masthead.inc +++ b/koha-tmpl/opac-tmpl/prog/en/includes/masthead.inc @@ -177,13 +177,13 @@
    diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt index b71a1ee..5cc3bbf 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt @@ -26,7 +26,7 @@ [% END %] [% IF ( CAN_user_tools_edit_notices ) %] -
    Notices
    +
    Notices & Slips
    Define notices (print and email notification messages for overdues, etc.)
    [% END %] diff --git a/members/memberentry.pl b/members/memberentry.pl index 86dd6ed..c474a66 100755 --- a/members/memberentry.pl +++ b/members/memberentry.pl @@ -347,10 +347,7 @@ if ((!$nok) and $nodouble and ($op eq 'insert' or $op eq 'save')){ # if we manage to find a valid email address, send notice if ($emailaddr) { $newdata{emailaddr} = $emailaddr; - my $letter = getletter ('members', "ACCTDETAILS:$newdata{'branchcode'}") ; - # if $branch notice fails, then email a default notice instead. - $letter = getletter ('members', "ACCTDETAILS") if !$letter; - SendAlerts ( 'members' , \%newdata , $letter ) if $letter + SendAlerts ( 'members', \%newdata, "ACCTDETAILS" ); } } diff --git a/members/moremember.pl b/members/moremember.pl index c477100..5a988f9 100755 --- a/members/moremember.pl +++ b/members/moremember.pl @@ -51,7 +51,6 @@ use C4::Reserves; use C4::Branch; # GetBranchName use C4::Overdues qw/CheckBorrowerDebarred/; use C4::Form::MessagingPreferences; -use C4::NewsChannels; #get slip news use List::MoreUtils qw/uniq/; use C4::Members::Attributes qw(GetBorrowerAttributes); @@ -484,13 +483,4 @@ $template->param( activeBorrowerRelationship => (C4::Context->preference('borrowerRelationship') ne ''), ); -#Get the slip news items -my $all_koha_news = &GetNewsToDisplay("slip"); -my $koha_news_count = scalar @$all_koha_news; - -$template->param( - koha_news => $all_koha_news, - koha_news_count => $koha_news_count -); - output_html_with_http_headers $input, $cookie, $template->output; diff --git a/members/printslip.pl b/members/printslip.pl new file mode 100755 index 0000000..3a499cd --- /dev/null +++ b/members/printslip.pl @@ -0,0 +1,92 @@ +#!/usr/bin/perl + +# Copyright 2000-2002 Katipo Communications +# Copyright 2010 BibLibre +# +# 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +=head1 moremember.pl + + script to do a borrower enquiry/bring up borrower details etc + Displays all the details about a borrower + written 20/12/99 by chris at katipo.co.nz + last modified 21/1/2000 by chris at katipo.co.nz + modified 31/1/2001 by chris at katipo.co.nz + to not allow items on request to be renewed + + needs html removed and to use the C4::Output more, but its tricky + +=cut + +use strict; +#use warnings; FIXME - Bug 2505 +use CGI; +use C4::Context; +use C4::Auth qw/:DEFAULT get_session/; +use C4::Output; +use C4::Members; +use C4::Koha; + +#use Smart::Comments; +#use Data::Dumper; + +use vars qw($debug); + +BEGIN { + $debug = $ENV{DEBUG} || 0; +} + +my $input = new CGI; +my $sessionID = $input->cookie("CGISESSID"); +my $session = get_session($sessionID); + +$debug or $debug = $input->param('debug') || 0; +my $print = $input->param('print'); +my $error = $input->param('error'); + +# circ staff who process checkouts but can't edit +# patrons still need to be able to print receipts +my $flagsrequired = { circulate => "circulate_remaining_permissions" }; + +my ( $template, $loggedinuser, $cookie ) = get_template_and_user( + { + template_name => "circ/printslip.tmpl", + query => $input, + type => "intranet", + authnotrequired => 0, + flagsrequired => $flagsrequired, + debug => 1, + } +); + +my $borrowernumber = $input->param('borrowernumber'); +my $branch=C4::Context->userenv->{'branch'}; +my ($slip, $is_html); +if (my $letter = IssueSlip ($session->param('branch') || $branch, $borrowernumber, $print eq "qslip")) { + $slip = $letter->{content}; + $is_html = $letter->{is_html}; +} + +$template->param( + slip => $slip, + plain => !$is_html, + title => "Print Receipt for $borrowernumber", + stylesheet => C4::Context->preference("SlipCSS"), + error => $error, +); + +output_html_with_http_headers $input, $cookie, $template->output; diff --git a/misc/cronjobs/advance_notices.pl b/misc/cronjobs/advance_notices.pl index 1fa358f..09c4017 100755 --- a/misc/cronjobs/advance_notices.pl +++ b/misc/cronjobs/advance_notices.pl @@ -79,13 +79,10 @@ patrons. It queues them in the message queue, which is processed by the process_message_queue.pl cronjob. See the comments in the script for directions on changing the script. This script has the following parameters : - -c Confirm and remove this help & warning - -m maximum number of days in advance to send advance notices. - -n send No mail. Instead, all mail messages are printed on screen. Usefull for testing purposes. - -v verbose - -i csv list of fields that get substituted into templates in places - of the EEitems.contentEE placeholder. Defaults to - issuedate,title,barcode,author + -c Confirm and remove this help & warning + -m maximum number of days in advance to send advance notices. + -n send No mail. Instead, all mail messages are printed on screen. Usefull for testing purposes. + -v verbose ENDUSAGE # Since advance notice options are not visible in the web-interface @@ -157,8 +154,6 @@ UPCOMINGITEM: foreach my $upcoming ( @$upcoming_dues ) { } else { my $biblio = C4::Biblio::GetBiblioFromItemNumber( $upcoming->{'itemnumber'} ); my $letter_type = 'DUE'; - $letter = C4::Letters::getletter( 'circulation', $letter_type ); - die "no letter of type '$letter_type' found. Please see sample_notices.sql" unless $letter; $sth->execute($upcoming->{'borrowernumber'},$upcoming->{'itemnumber'},'0'); my $titles = ""; while ( my $item_info = $sth->fetchrow_hashref()) { @@ -166,13 +161,14 @@ UPCOMINGITEM: foreach my $upcoming ( @$upcoming_dues ) { $titles .= join("\t", at item_info) . "\n"; } - $letter = parse_letter( { letter => $letter, + $letter = parse_letter( { letter_code => $letter_type, borrowernumber => $upcoming->{'borrowernumber'}, branchcode => $upcoming->{'branchcode'}, biblionumber => $biblio->{'biblionumber'}, itemnumber => $upcoming->{'itemnumber'}, substitute => { 'items.content' => $titles } - } ); + } ) + or die "no letter of type '$letter_type' found. Please see sample_notices.sql"; } } else { $borrower_preferences = C4::Members::Messaging::GetMessagingPreferences( { borrowernumber => $upcoming->{'borrowernumber'}, @@ -189,8 +185,6 @@ UPCOMINGITEM: foreach my $upcoming ( @$upcoming_dues ) { } else { my $biblio = C4::Biblio::GetBiblioFromItemNumber( $upcoming->{'itemnumber'} ); my $letter_type = 'PREDUE'; - $letter = C4::Letters::getletter( 'circulation', $letter_type ); - die "no letter of type '$letter_type' found. Please see sample_notices.sql" unless $letter; $sth->execute($upcoming->{'borrowernumber'},$upcoming->{'itemnumber'},$borrower_preferences->{'days_in_advance'}); my $titles = ""; while ( my $item_info = $sth->fetchrow_hashref()) { @@ -198,13 +192,14 @@ UPCOMINGITEM: foreach my $upcoming ( @$upcoming_dues ) { $titles .= join("\t", at item_info) . "\n"; } - $letter = parse_letter( { letter => $letter, + $letter = parse_letter( { letter_code => $letter_type, borrowernumber => $upcoming->{'borrowernumber'}, branchcode => $upcoming->{'branchcode'}, biblionumber => $biblio->{'biblionumber'}, itemnumber => $upcoming->{'itemnumber'}, substitute => { 'items.content' => $titles } - } ); + } ) + or die "no letter of type '$letter_type' found. Please see sample_notices.sql"; } } @@ -250,8 +245,6 @@ PATRON: while ( my ( $borrowernumber, $digest ) = each %$upcoming_digest ) { my $letter_type = 'PREDUEDGST'; - my $letter = C4::Letters::getletter( 'circulation', $letter_type ); - die "no letter of type '$letter_type' found. Please see sample_notices.sql" unless $letter; $sth->execute($borrowernumber,$borrower_preferences->{'days_in_advance'}); my $titles = ""; @@ -259,12 +252,13 @@ PATRON: while ( my ( $borrowernumber, $digest ) = each %$upcoming_digest ) { my @item_info = map { $_ =~ /^date|date$/ ? format_date($item_info->{$_}) : $item_info->{$_} || '' } @item_content_fields; $titles .= join("\t", at item_info) . "\n"; } - $letter = parse_letter( { letter => $letter, + my $letter = parse_letter( { letter_code => $letter_type, borrowernumber => $borrowernumber, substitute => { count => $count, 'items.content' => $titles } - } ); + } ) + or die "no letter of type '$letter_type' found. Please see sample_notices.sql"; if ($nomail) { local $, = "\f"; print $letter->{'content'}; @@ -290,20 +284,19 @@ PATRON: while ( my ( $borrowernumber, $digest ) = each %$due_digest ) { next PATRON unless $borrower_preferences; # how could this happen? my $letter_type = 'DUEDGST'; - my $letter = C4::Letters::getletter( 'circulation', $letter_type ); - die "no letter of type '$letter_type' found. Please see sample_notices.sql" unless $letter; $sth->execute($borrowernumber,'0'); my $titles = ""; while ( my $item_info = $sth->fetchrow_hashref()) { my @item_info = map { $_ =~ /^date|date$/ ? format_date($item_info->{$_}) : $item_info->{$_} || '' } @item_content_fields; $titles .= join("\t", at item_info) . "\n"; } - $letter = parse_letter( { letter => $letter, + my $letter = parse_letter( { letter_code => $letter_type, borrowernumber => $borrowernumber, substitute => { count => $count, 'items.content' => $titles } - } ); + } ) + or die "no letter of type '$letter_type' found. Please see sample_notices.sql"; if ($nomail) { local $, = "\f"; @@ -323,40 +316,35 @@ PATRON: while ( my ( $borrowernumber, $digest ) = each %$due_digest ) { =head2 parse_letter - - =cut sub parse_letter { my $params = shift; - foreach my $required ( qw( letter borrowernumber ) ) { + foreach my $required ( qw( letter_code borrowernumber ) ) { return unless exists $params->{$required}; } - if ( $params->{'substitute'} ) { - while ( my ($key, $replacedby) = each %{$params->{'substitute'}} ) { - my $replacefield = "<<$key>>"; - - $params->{'letter'}->{title} =~ s/$replacefield/$replacedby/g; - $params->{'letter'}->{content} =~ s/$replacefield/$replacedby/g; - } - } - - C4::Letters::parseletter( $params->{'letter'}, 'borrowers', $params->{'borrowernumber'} ); + my %table_params = ( 'borrowers' => $params->{'borrowernumber'} ); - if ( $params->{'branchcode'} ) { - C4::Letters::parseletter( $params->{'letter'}, 'branches', $params->{'branchcode'} ); + if ( my $p = $params->{'branchcode'} ) { + $table_params{'branches'} = $p; } - if ( $params->{'itemnumber'} ) { - C4::Letters::parseletter( $params->{'letter'}, 'issues', $params->{'itemnumber'} ); - C4::Letters::parseletter( $params->{'letter'}, 'items', $params->{'itemnumber'} ); + if ( my $p = $params->{'itemnumber'} ) { + $table_params{'issues'} = $p; + $table_params{'items'} = $p; } - if ( $params->{'biblionumber'} ) { - C4::Letters::parseletter( $params->{'letter'}, 'biblio', $params->{'biblionumber'} ); - C4::Letters::parseletter( $params->{'letter'}, 'biblioitems', $params->{'biblionumber'} ); + if ( my $p = $params->{'biblionumber'} ) { + $table_params{'biblio'} = $p; + $table_params{'biblioitems'} = $p; } - return $params->{'letter'}; + return C4::Letters::GetPreparedLetter ( + module => 'circulation', + letter_code => $params->{'letter_code'}, + branchcode => $table_params{'branches'}, + substitute => $params->{'substitute'}, + tables => \%table_params, + ); } 1; diff --git a/misc/cronjobs/gather_print_notices.pl b/misc/cronjobs/gather_print_notices.pl index a72d6a6..165b16e 100755 --- a/misc/cronjobs/gather_print_notices.pl +++ b/misc/cronjobs/gather_print_notices.pl @@ -39,11 +39,9 @@ use Getopt::Long; sub usage { print STDERR < \$stylesheet, 'h|help' => \$help, ) || usage( 1 ); @@ -71,16 +68,9 @@ exit unless( @messages ); open OUTPUT, '>', File::Spec->catdir( $output_directory, "holdnotices-" . $today->output( 'iso' ) . ".html" ); my $template = C4::Templates::gettemplate( 'batch/print-notices.tmpl', 'intranet', new CGI ); -my $stylesheet_contents = ''; - -if ($stylesheet) { - open STYLESHEET, '<', $stylesheet; - while ( ) { $stylesheet_contents .= $_ } - close STYLESHEET; -} $template->param( - stylesheet => $stylesheet_contents, + stylesheet => C4::Context->preference("NoticeCSS"), today => $today->output(), messages => \@messages, ); diff --git a/misc/cronjobs/overdue_notices.pl b/misc/cronjobs/overdue_notices.pl index 5896abd..d303f4f 100755 --- a/misc/cronjobs/overdue_notices.pl +++ b/misc/cronjobs/overdue_notices.pl @@ -460,16 +460,6 @@ END_SQL { $verbose and warn "borrower $firstname, $lastname ($borrowernumber) has items triggering level $i."; - my $letter = C4::Letters::getletter( 'circulation', $overdue_rules->{"letter$i"} ); - - unless ($letter) { - $verbose and warn "Message '$overdue_rules->{letter$i}' content not found"; - - # might as well skip while PERIOD, no other borrowers are going to work. - # FIXME : Does this mean a letter must be defined in order to trigger a debar ? - next PERIOD; - } - if ( $overdue_rules->{"debarred$i"} ) { #action taken is debarring @@ -494,11 +484,12 @@ END_SQL my @item_info = map { $_ =~ /^date|date$/ ? format_date( $item_info->{$_} ) : $item_info->{$_} || '' } @item_content_fields; $titles .= join("\t", @item_info) . "\n"; $itemcount++; - push @items, { itemnumber => $item_info->{'itemnumber'}, biblionumber => $item_info->{'biblionumber'} }; + push @items, $item_info; } $sth2->finish; - $letter = parse_letter( - { letter => $letter, + + my $letter = parse_letter( + { letter_code => $overdue_rules->{"letter$i"}, borrowernumber => $borrowernumber, branchcode => $branchcode, items => \@items, @@ -509,6 +500,13 @@ END_SQL } } ); + unless ($letter) { + $verbose and warn "Message '$overdue_rules->{letter$i}' content not found"; + + # might as well skip while PERIOD, no other borrowers are going to work. + # FIXME : Does this mean a letter must be defined in order to trigger a debar ? + next PERIOD; + } if ( $exceededPrintNoticesMaxLines ) { $letter->{'content'} .= "List too long for form; please check your account online for a complete list of your overdue items."; @@ -643,54 +641,56 @@ substituted keys and values. =cut -sub parse_letter { # FIXME: this code should probably be moved to C4::Letters:parseletter +sub parse_letter { my $params = shift; - foreach my $required (qw( letter borrowernumber )) { + foreach my $required (qw( letter_code borrowernumber )) { return unless exists $params->{$required}; } - my $todaysdate = C4::Dates->new()->output("syspref"); - $params->{'letter'}->{title} =~ s/<>/$todaysdate/g; - $params->{'letter'}->{content} =~ s/<>/$todaysdate/g; + my $substitute = $params->{'substitute'} || {}; + $substitute->{today} ||= C4::Dates->new()->output("syspref"); - if ( $params->{'substitute'} ) { - while ( my ( $key, $replacedby ) = each %{ $params->{'substitute'} } ) { - my $replacefield = "<<$key>>"; - $params->{'letter'}->{title} =~ s/$replacefield/$replacedby/g; - $params->{'letter'}->{content} =~ s/$replacefield/$replacedby/g; - } + my %tables = ( 'borrowers' => $params->{'borrowernumber'} ); + if ( my $p = $params->{'branchcode'} ) { + $tables{'branches'} = $p; } - $params->{'letter'} = C4::Letters::parseletter( $params->{'letter'}, 'borrowers', $params->{'borrowernumber'} ); - - if ( $params->{'branchcode'} ) { - $params->{'letter'} = C4::Letters::parseletter( $params->{'letter'}, 'branches', $params->{'branchcode'} ); + my $currency_format; + if ($params->{'letter'}->{'content'} =~ m/(.*)<\/fine>/o) { # process any fine tags... + $currency_format = $1; + $params->{'letter'}->{'content'} =~ s/.*<\/fine>/<>/o; } - if ( $params->{'items'} ) { + my @item_tables; + if ( my $i = $params->{'items'} ) { my $item_format = ''; - PROCESS_ITEMS: - while (scalar(@{$params->{'items'}}) > 0) { - my $item = shift @{$params->{'items'}}; + foreach my $item (@$i) { my $fine = GetFine($item->{'itemnumber'}, $params->{'borrowernumber'}); if (!$item_format) { $params->{'letter'}->{'content'} =~ m/(.*<\/item>)/; $item_format = $1; } - if ($params->{'letter'}->{'content'} =~ m/(.*)<\/fine>/) { # process any fine tags... - my $formatted_fine = currency_format("$1", "$fine", FMT_SYMBOL); - $params->{'letter'}->{'content'} =~ s/.*<\/fine>/$formatted_fine/; - } - $params->{'letter'} = C4::Letters::parseletter( $params->{'letter'}, 'biblio', $item->{'biblionumber'} ); - $params->{'letter'} = C4::Letters::parseletter( $params->{'letter'}, 'biblioitems', $item->{'biblionumber'} ); - $params->{'letter'} = C4::Letters::parseletter( $params->{'letter'}, 'items', $item->{'itemnumber'} ); - $params->{'letter'} = C4::Letters::parseletter( $params->{'letter'}, 'issues', $item->{'itemnumber'} ); - $params->{'letter'}->{'content'} =~ s/(.*<\/item>)/$1\n$item_format/ if scalar(@{$params->{'items'}} > 0); + $item->{'fine'} = currency_format($currency_format, "$fine", FMT_SYMBOL) + if $currency_format; + + push @item_tables, { + 'biblio' => $item->{'biblionumber'}, + 'biblioitems' => $item->{'biblionumber'}, + 'items' => $item, + 'issues' => $item->{'itemnumber'}, + }; } } - $params->{'letter'}->{'content'} =~ s/<\/{0,1}?item>//g; # strip all remaining item tags... - return $params->{'letter'}; + + return C4::Letters::GetPreparedLetter ( + module => 'circulation', + letter_code => $params->{'letter_code'}, + branchcode => $params->{'branchcode'}, + tables => \%tables, + substitute => $substitute, + repeat => { item => \@item_tables }, + ); } =head2 prepare_letter_for_printing diff --git a/t/db_dependent/lib/KohaTest/Letters.pm b/t/db_dependent/lib/KohaTest/Letters.pm index 97d58fb..f2d7b0d 100644 --- a/t/db_dependent/lib/KohaTest/Letters.pm +++ b/t/db_dependent/lib/KohaTest/Letters.pm @@ -12,13 +12,12 @@ sub testing_class { 'C4::Letters' }; sub methods : Test( 1 ) { my $self = shift; - my @methods = qw( getletter - addalert + my @methods = qw( addalert delalert getalert findrelatedto SendAlerts - parseletter + GetPreparedLetter ); can_ok( $self->testing_class, @methods ); diff --git a/t/db_dependent/lib/KohaTest/Letters/GetLetter.pm b/t/db_dependent/lib/KohaTest/Letters/GetLetter.pm index 76b6ab4..53e5439 100644 --- a/t/db_dependent/lib/KohaTest/Letters/GetLetter.pm +++ b/t/db_dependent/lib/KohaTest/Letters/GetLetter.pm @@ -10,7 +10,7 @@ use Test::More; sub GetLetter : Test( 6 ) { my $self = shift; - my $letter = getletter( 'circulation', 'ODUE' ); + my $letter = getletter( 'circulation', 'ODUE', '' ); isa_ok( $letter, 'HASH' ) or diag( Data::Dumper->Dump( [ $letter ], [ 'letter' ] ) ); @@ -21,7 +21,6 @@ sub GetLetter : Test( 6 ) { ok( exists $letter->{'name'}, 'name' ); ok( exists $letter->{'title'}, 'title' ); - } 1; diff --git a/t/db_dependent/lib/KohaTest/Members.pm b/t/db_dependent/lib/KohaTest/Members.pm index 5646be1..dfde7da 100644 --- a/t/db_dependent/lib/KohaTest/Members.pm +++ b/t/db_dependent/lib/KohaTest/Members.pm @@ -52,6 +52,7 @@ sub methods : Test( 1 ) { GetBorrowersWhoHaveNeverBorrowed GetBorrowersWithIssuesHistoryOlderThan GetBorrowersNamesAndLatestIssue + IssueSlip ); can_ok( $self->testing_class, @methods ); diff --git a/t/db_dependent/lib/KohaTest/Print.pm b/t/db_dependent/lib/KohaTest/Print.pm index 02fd5fb..d35ab34 100644 --- a/t/db_dependent/lib/KohaTest/Print.pm +++ b/t/db_dependent/lib/KohaTest/Print.pm @@ -12,10 +12,7 @@ sub testing_class { 'C4::Print' }; sub methods : Test( 1 ) { my $self = shift; - my @methods = qw( remoteprint - printreserve - printslip - ); + my @methods = qw( printslip ); can_ok( $self->testing_class, @methods ); } diff --git a/t/db_dependent/lib/KohaTest/Reserves.pm b/t/db_dependent/lib/KohaTest/Reserves.pm index 8b05dd0..6416ac3 100644 --- a/t/db_dependent/lib/KohaTest/Reserves.pm +++ b/t/db_dependent/lib/KohaTest/Reserves.pm @@ -33,6 +33,7 @@ sub methods : Test( 1 ) { GetReserveInfo _FixPriority _Findgroupreserve + ReserveSlip ); can_ok( $self->testing_class, @methods ); diff --git a/tools/letter.pl b/tools/letter.pl index 04cd7d2..ae47810 100755 --- a/tools/letter.pl +++ b/tools/letter.pl @@ -46,14 +46,35 @@ use CGI; use C4::Auth; use C4::Context; use C4::Output; +use C4::Branch; # GetBranches +use C4::Members::Attributes; -# letter_exists($module, $code) -# - return true if a letter with the given $module and $code exists +# _letter_from_where($branchcode,$module, $code) +# - return FROM WHERE clause and bind args for a letter +sub _letter_from_where { + my ($branchcode, $module, $code) = @_; + my $sql = q{FROM letter WHERE branchcode = ? AND module = ? AND code = ?}; + my @args = ($branchcode || '', $module, $code); +# Mysql is retarded. cause branchcode is part of the primary key it cannot be null. How does that +# work with foreign key constraint I wonder... + +# if ($branchcode) { +# $sql .= " AND branchcode = ?"; +# push @args, $branchcode; +# } else { +# $sql .= " AND branchcode IS NULL"; +# } + + return ($sql, \@args); +} + +# letter_exists($branchcode,$module, $code) +# - return true if a letter with the given $branchcode, $module and $code exists sub letter_exists { - my ($module, $code) = @_; + my ($sql, $args) = _letter_from_where(@_); my $dbh = C4::Context->dbh; - my $letters = $dbh->selectall_arrayref(q{SELECT name FROM letter WHERE module = ? AND code = ?}, undef, $module, $code); - return @{$letters}; + my $letter = $dbh->selectrow_hashref("SELECT * $sql", undef, @$args); + return $letter; } # $protected_letters = protected_letters() @@ -67,16 +88,14 @@ sub protected_letters { my $input = new CGI; my $searchfield = $input->param('searchfield'); my $script_name = '/cgi-bin/koha/tools/letter.pl'; +my $branchcode = $input->param('branchcode'); my $code = $input->param('code'); my $module = $input->param('module'); my $content = $input->param('content'); -my $op = $input->param('op'); +my $op = $input->param('op') || ''; my $dbh = C4::Context->dbh; -if (!defined $module ) { - $module = q{}; -} -my ( $template, $borrowernumber, $cookie ) = get_template_and_user( +my ( $template, $borrowernumber, $cookie, $staffflags ) = get_template_and_user( { template_name => 'tools/letter.tmpl', query => $input, @@ -87,32 +106,39 @@ my ( $template, $borrowernumber, $cookie ) = get_template_and_user( } ); -if (!defined $op) { - $op = q{}; # silence errors from eq -} +my $my_branch = C4::Context->preference("IndependantBranches") && !$staffflags->{'superlibrarian'} + ? C4::Context->userenv()->{'branch'} + : undef; # we show only the TMPL_VAR names $op $template->param( + independant_branch => $my_branch, script_name => $script_name, + searchfield => $searchfield, action => $script_name ); +if ($op eq 'copy') { + add_copy(); + $op = 'add_form'; +} + if ($op eq 'add_form') { - add_form($module, $code); + add_form($branchcode, $module, $code); } elsif ( $op eq 'add_validate' ) { add_validate(); $op = q{}; # next operation is to return to default screen } elsif ( $op eq 'delete_confirm' ) { - delete_confirm($module, $code); + delete_confirm($branchcode, $module, $code); } elsif ( $op eq 'delete_confirmed' ) { - delete_confirmed($module, $code); + delete_confirmed($branchcode, $module, $code); $op = q{}; # next operation is to return to default screen } else { - default_display($searchfield); + default_display($branchcode,$searchfield); } # Do this last as delete_confirmed resets @@ -125,23 +151,21 @@ if ($op) { output_html_with_http_headers $input, $cookie, $template->output; sub add_form { - my ($module, $code ) = @_; + my ($branchcode,$module, $code ) = @_; my $letter; # if code has been passed we can identify letter and its an update action if ($code) { - $letter = $dbh->selectrow_hashref(q{SELECT module, code, name, title, content FROM letter WHERE module=? AND code=?}, - undef, $module, $code); + $letter = letter_exists($branchcode,$module, $code); + } + if ($letter) { $template->param( modify => 1 ); $template->param( code => $letter->{code} ); } else { # initialize the new fields $letter = { - module => $module, - code => q{}, - name => q{}, - title => q{}, - content => q{}, + branchcode => $branchcode, + module => $module, }; $template->param( adding => 1 ); } @@ -173,14 +197,20 @@ sub add_form { {value => q{}, text => '---ITEMS---' }, {value => 'items.content', text => 'items.content'}, add_fields('issues','borrowers'); + if ($module eq 'circulation') { + push @{$field_selection}, add_fields('opac_news'); + } } $template->param( - name => $letter->{name}, - title => $letter->{title}, - content => $letter->{content}, - module => $module, - $module => 1, + branchcode => $letter->{branchcode}, + name => $letter->{name}, + is_html => $letter->{is_html}, + title => $letter->{title}, + content => $letter->{content}, + module => $module, + $module => 1, + branchloop => _branchloop($branchcode), SQLfieldname => $field_selection, ); return; @@ -188,37 +218,56 @@ sub add_form { sub add_validate { my $dbh = C4::Context->dbh; - my $module = $input->param('module'); - my $oldmodule = $input->param('oldmodule'); - my $code = $input->param('code'); - my $name = $input->param('name'); - my $title = $input->param('title'); - my $content = $input->param('content'); - if (letter_exists($oldmodule, $code)) { + my $oldbranchcode = $input->param('oldbranchcode'); + my $branchcode = $input->param('branchcode') || ''; + my $module = $input->param('module'); + my $oldmodule = $input->param('oldmodule'); + my $code = $input->param('code'); + my $name = $input->param('name'); + my $is_html = $input->param('is_html'); + my $title = $input->param('title'); + my $content = $input->param('content'); + if (letter_exists($oldbranchcode,$oldmodule, $code)) { $dbh->do( - q{UPDATE letter SET module = ?, code = ?, name = ?, title = ?, content = ? WHERE module = ? AND code = ?}, + q{UPDATE letter SET branchcode = ?, module = ?, name = ?, is_html = ?, title = ?, content = ? WHERE branchcode = ? AND module = ? AND code = ?}, undef, - $module, $code, $name, $title, $content, - $oldmodule, $code + $branchcode, $module, $name, $is_html || 0, $title, $content, + $oldbranchcode, $oldmodule, $code ); } else { $dbh->do( - q{INSERT INTO letter (module,code,name,title,content) VALUES (?,?,?,?,?)}, + q{INSERT INTO letter (branchcode,module,code,name,is_html,title,content) VALUES (?,?,?,?,?,?,?)}, undef, - $module, $code, $name, $title, $content + $branchcode, $module, $code, $name, $is_html || 0, $title, $content ); } # set up default display - default_display(); - return; + default_display($branchcode); +} + +sub add_copy { + my $dbh = C4::Context->dbh; + my $oldbranchcode = $input->param('oldbranchcode'); + my $branchcode = $input->param('branchcode'); + my $module = $input->param('module'); + my $code = $input->param('code'); + + return if letter_exists($branchcode,$module, $code); + + my $old_letter = letter_exists($oldbranchcode,$module, $code); + + $dbh->do( + q{INSERT INTO letter (branchcode,module,code,name,is_html,title,content) VALUES (?,?,?,?,?,?,?)}, + undef, + $branchcode, $module, $code, $old_letter->{name}, $old_letter->{is_html}, $old_letter->{title}, $old_letter->{content} + ); } sub delete_confirm { - my ($module, $code) = @_; + my ($branchcode, $module, $code) = @_; my $dbh = C4::Context->dbh; - my $letter = $dbh->selectrow_hashref(q|SELECT name FROM letter WHERE module = ? AND code = ?|, - { Slice => {} }, - $module, $code); + my $letter = letter_exists($branchcode, $module, $code); + $template->param( branchcode => $branchcode, branchname => GetBranchName($branchcode) ); $template->param( code => $code ); $template->param( module => $module); $template->param( name => $letter->{name}); @@ -226,40 +275,53 @@ sub delete_confirm { } sub delete_confirmed { - my ($module, $code) = @_; + my ($branchcode, $module, $code) = @_; + my ($sql, $args) = _letter_from_where($branchcode, $module, $code); my $dbh = C4::Context->dbh; - $dbh->do('DELETE FROM letter WHERE module=? AND code=?',{},$module,$code); + $dbh->do("DELETE $sql", undef, @$args); # setup default display for screen - default_display(); + default_display($branchcode); return; } sub retrieve_letters { - my $searchstring = shift; + my ($branchcode, $searchstring) = @_; + + $branchcode = $my_branch if $branchcode && $my_branch; + my $dbh = C4::Context->dbh; - if ($searchstring) { - if ($searchstring=~m/(\S+)/) { - $searchstring = $1 . q{%}; - return $dbh->selectall_arrayref('SELECT module, code, name FROM letter WHERE code LIKE ? ORDER BY module, code', - { Slice => {} }, $searchstring); - } + my ($sql, @where, @args); + $sql = "SELECT branchcode, module, code, name, branchname + FROM letter + LEFT OUTER JOIN branches USING (branchcode)"; + if ($searchstring && $searchstring=~m/(\S+)/) { + $searchstring = $1 . q{%}; + push @where, 'code LIKE ?'; + push @args, $searchstring; } - else { - return $dbh->selectall_arrayref('SELECT module, code, name FROM letter ORDER BY module, code', { Slice => {} }); + elsif ($branchcode) { + push @where, 'branchcode = ?'; + push @args, $branchcode || ''; } - return; + elsif ($my_branch) { + push @where, "(branchcode = ? OR branchcode = '')"; + push @args, $my_branch; + } + + $sql .= " WHERE ".join(" AND ", @where) if @where; + $sql .= " ORDER BY module, code, branchcode"; +# use Data::Dumper; die Dumper($sql, \@args); + return $dbh->selectall_arrayref($sql, { Slice => {} }, @args); } sub default_display { - my $searchfield = shift; - my $results; + my ($branchcode, $searchfield) = @_; + if ( $searchfield ) { $template->param( search => 1 ); - $template->param( searchfield => $searchfield ); - $results = retrieve_letters($searchfield); - } else { - $results = retrieve_letters(); } + my $results = retrieve_letters($branchcode,$searchfield); + my $loop_data = []; my $protected_letters = protected_letters(); foreach my $row (@{$results}) { @@ -267,8 +329,27 @@ sub default_display { push @{$loop_data}, $row; } - $template->param( letter => $loop_data ); - return; + + $template->param( + letter => $loop_data, + branchloop => _branchloop($branchcode), + ); +} + +sub _branchloop { + my ($branchcode) = @_; + + my $branches = GetBranches(); + my @branchloop; + for my $thisbranch (sort { $branches->{$a}->{branchname} cmp $branches->{$b}->{branchname} } keys %$branches) { + push @branchloop, { + value => $thisbranch, + selected => $branchcode && $thisbranch eq $branchcode, + branchname => $branches->{$thisbranch}->{'branchname'}, + }; + } + + return \@branchloop; } sub add_fields { @@ -307,6 +388,7 @@ sub get_columns_for { text => $tlabel, }; } + my $sql = "SHOW COLUMNS FROM $table";# TODO not db agnostic my $table_prefix = $table . q|.|; my $rows = C4::Context->dbh->selectall_arrayref($sql, { Slice => {} }); @@ -317,5 +399,15 @@ sub get_columns_for { text => $table_prefix . $row->{Field}, } } + if ($table eq 'borrowers') { + if ( my $attributes = C4::Members::Attributes::GetAttributes() ) { + foreach (@$attributes) { + push @fields, { + value => "borrower-attribute:$_", + text => "attribute:$_", + } + } + } + } return @fields; } -- 1.6.5 From srdjan at catalyst.net.nz Wed Feb 22 06:49:30 2012 From: srdjan at catalyst.net.nz (Srdjan Jankovic) Date: Wed, 22 Feb 2012 18:49:30 +1300 Subject: [Koha-patches] [PATCH] bug_7001: Issue and Reserve slips are notices. In-Reply-To: References: Message-ID: <1329889770-12936-1-git-send-email-srdjan@catalyst.net.nz> Branches can have their own version of notices - added branchcode to letter table. Support html notices - added is_html to letter table. Support for borrower attributes in templates. GetPreparedletter() is the interface for compiling letters (notices). Sysprefs for notice and slips stylesheets. --- C4/Circulation.pm | 20 +- C4/Letters.pm | 549 +++++++++++++------- C4/Members.pm | 81 +++- C4/Members/Attributes.pm | 18 + C4/Message.pm | 12 +- C4/Print.pm | 146 ++---- C4/Reserves.pm | 103 +++-- C4/Suggestions.pm | 22 +- acqui/booksellers.pl | 7 +- circ/circulation.pl | 3 +- circ/hold-transfer-slip.pl | 32 +- .../data/mysql/de-DE/mandatory/sample_notices.sql | 2 +- .../data/mysql/en/mandatory/sample_notices.sql | 84 +++- .../data/mysql/es-ES/mandatory/sample_notices.sql | 2 +- .../mysql/fr-FR/1-Obligatoire/sample_notices.sql | 2 +- installer/data/mysql/it-IT/necessari/notices.sql | 2 +- installer/data/mysql/kohastructure.sql | 7 +- .../mysql/nb-NO/1-Obligatorisk/sample_notices.sql | 2 +- .../data/mysql/pl-PL/mandatory/sample_notices.sql | 2 +- .../data/mysql/ru-RU/mandatory/sample_notices.sql | 2 +- installer/data/mysql/sysprefs.sql | 2 + .../data/mysql/uk-UA/mandatory/sample_notices.sql | 2 +- installer/data/mysql/updatedatabase.pl | 100 ++++- .../prog/en/includes/circ-toolbar.inc | 4 +- .../en/modules/admin/preferences/circulation.pref | 5 + .../en/modules/admin/preferences/staff_client.pref | 5 + .../prog/en/modules/batch/print-notices.tt | 6 +- .../prog/en/modules/circ/hold-transfer-slip.tt | 54 -- .../prog/en/modules/circ/printslip.tt | 28 + .../intranet-tmpl/prog/en/modules/tools/letter.tt | 162 +++++-- .../prog/en/modules/tools/tools-home.tt | 2 +- members/memberentry.pl | 5 +- members/moremember.pl | 10 - members/printslip.pl | 92 ++++ misc/cronjobs/advance_notices.pl | 78 ++-- misc/cronjobs/gather_print_notices.pl | 14 +- misc/cronjobs/overdue_notices.pl | 86 ++-- t/db_dependent/lib/KohaTest/Letters.pm | 5 +- t/db_dependent/lib/KohaTest/Letters/GetLetter.pm | 3 +- t/db_dependent/lib/KohaTest/Members.pm | 1 + t/db_dependent/lib/KohaTest/Print.pm | 5 +- t/db_dependent/lib/KohaTest/Reserves.pm | 1 + tools/letter.pl | 230 ++++++--- 43 files changed, 1308 insertions(+), 690 deletions(-) delete mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/circ/hold-transfer-slip.tt create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/circ/printslip.tt create mode 100755 members/printslip.pl diff --git a/C4/Circulation.pm b/C4/Circulation.pm index 93c6fac..a62f26e 100644 --- a/C4/Circulation.pm +++ b/C4/Circulation.pm @@ -2667,11 +2667,18 @@ sub SendCirculationAlert { borrowernumber => $borrower->{borrowernumber}, message_name => $message_name{$type}, }); - my $letter = C4::Letters::getletter('circulation', $type); - C4::Letters::parseletter($letter, 'biblio', $item->{biblionumber}); - C4::Letters::parseletter($letter, 'biblioitems', $item->{biblionumber}); - C4::Letters::parseletter($letter, 'borrowers', $borrower->{borrowernumber}); - C4::Letters::parseletter($letter, 'branches', $branch); + my $letter = C4::Letters::GetPreparedLetter ( + module => 'circulation', + letter_code => $type, + branchcode => $branch, + tables => { + 'biblio' => $item->{biblionumber}, + 'biblioitems' => $item->{biblionumber}, + 'borrowers' => $borrower, + 'branches' => $branch, + } + ) or return; + my @transports = @{ $borrower_preferences->{transports} }; # warn "no transports" unless @transports; for (@transports) { @@ -2686,7 +2693,8 @@ sub SendCirculationAlert { $message->update; } } - $letter; + + return $letter; } =head2 updateWrongTransfer diff --git a/C4/Letters.pm b/C4/Letters.pm index 28c6984..5080a0c 100644 --- a/C4/Letters.pm +++ b/C4/Letters.pm @@ -24,6 +24,7 @@ use MIME::Lite; use Mail::Sendmail; use C4::Members; +use C4::Members::Attributes qw(GetBorrowerAttributes); use C4::Branch; use C4::Log; use C4::SMS; @@ -40,7 +41,7 @@ BEGIN { $VERSION = 3.01; @ISA = qw(Exporter); @EXPORT = qw( - &GetLetters &getletter &addalert &getalert &delalert &findrelatedto &SendAlerts GetPrintMessages + &GetLetters &GetPreparedLetter &GetWrappedLetter &addalert &getalert &delalert &findrelatedto &SendAlerts &GetPrintMessages ); } @@ -115,13 +116,26 @@ sub GetLetters (;$) { return \%letters; } -sub getletter ($$) { - my ( $module, $code ) = @_; +my %letter; +sub getletter ($$$) { + my ( $module, $code, $branchcode ) = @_; + + if (C4::Context->preference('IndependantBranches') && $branchcode){ + $branchcode = C4::Context->userenv->{'branch'}; + } + + if ( my $l = $letter{$module}{$code}{$branchcode} ) { + return { %$l }; # deep copy + } + 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; + my $sth = $dbh->prepare("select * from letter where module=? and code=? and (branchcode = ? or branchcode = '') order by branchcode desc limit 1"); + $sth->execute( $module, $code, $branchcode ); + my $line = $sth->fetchrow_hashref + or return; + $line->{'content-type'} = 'text/html; charset="UTF-8"' if $line->{is_html}; + $letter{$module}{$code}{$branchcode} = $line; + return { %$line }; } =head2 addalert ($borrowernumber, $type, $externalid) @@ -176,7 +190,7 @@ sub delalert ($) { sub getalert (;$$$) { my ( $borrowernumber, $type, $externalid ) = @_; my $dbh = C4::Context->dbh; - my $query = "SELECT * FROM alert WHERE"; + my $query = "SELECT a.*, b.branchcode FROM alert a JOIN borrowers b USING(borrowernumber) WHERE"; my @bind; if ($borrowernumber and $borrowernumber =~ /^\d+$/) { $query .= " borrowernumber=? AND "; @@ -232,73 +246,68 @@ sub findrelatedto ($$) { parameters : - $type : the type of alert - $externalid : the id of the "object" to query - - $letter : the letter to send. + - $letter_code : 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 ( $type, $externalid, $letter_code ) = @_; my $dbh = C4::Context->dbh; my $strsth; 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/<>/$userenv->{firstname}/g; - $letter->{content} =~ s/<>/$userenv->{surname}/g; - $letter->{content} =~ - s/<>/$userenv->{emailaddress}/g; - - # parsing biblio information - parseletter( $letter, 'biblio', $biblionumber ); - parseletter( $letter, 'biblioitems', $biblionumber ); + my ($biblionumber) = $sth->fetchrow + or warn( "No subscription for '$externalid'" ), + return; + my %letter; # find the list of borrowers to alert my $alerts = getalert( '', 'issue', $externalid ); foreach (@$alerts) { - # and parse borrower ... - my $innerletter = $letter; my $borinfo = C4::Members::GetMember('borrowernumber' => $_->{'borrowernumber'}); - parseletter( $innerletter, 'borrowers', $_->{'borrowernumber'} ); + my $email = $borinfo->{email} or next; + + # warn "sending issues..."; + my $userenv = C4::Context->userenv; + my $letter = GetPreparedLetter ( + module => 'serial', + letter_code => $letter_code, + branchcode => $userenv->{branch}, + tables => { + 'branches' => $_->{branchcode}, + 'biblio' => $biblionumber, + 'biblioitems' => $biblionumber, + 'borrowers' => $borinfo, + }, + want_librarian => 1, + ) or return; # ... then send mail - if ( $borinfo->{email} ) { - my %mail = ( - To => $borinfo->{email}, - From => $borinfo->{email}, - Subject => "" . $innerletter->{title}, - Message => "" . $innerletter->{content}, - 'Content-Type' => 'text/plain; charset="utf8"', - ); - sendmail(%mail) or carp $Mail::Sendmail::error; - - } + my %mail = ( + To => $email, + From => $email, + Subject => "" . $letter->{title}, + Message => "" . $letter->{content}, + 'Content-Type' => 'text/plain; charset="utf8"', + ); + sendmail(%mail) or carp $Mail::Sendmail::error; } } - elsif ( $type eq 'claimacquisition' ) { - - $letter = getletter( 'claimacquisition', $letter ); + elsif ( $type eq 'claimacquisition' or $type eq 'claimissues' ) { # prepare the letter... # search the biblionumber - $strsth = qq{ + $strsth = $type eq 'claimacquisition' + ? qq{ SELECT aqorders.*,aqbasket.*,biblio.*,biblioitems.*,aqbooksellers.* FROM aqorders LEFT JOIN aqbasket ON aqbasket.basketno=aqorders.basketno @@ -306,114 +315,83 @@ sub SendAlerts { LEFT JOIN biblioitems ON aqorders.biblioitemnumber=biblioitems.biblioitemnumber LEFT JOIN aqbooksellers ON aqbasket.booksellerid=aqbooksellers.id WHERE aqorders.ordernumber IN ( - } - . join( ",", @$externalid ) . ")"; - } - elsif ( $type eq 'claimissues' ) { - - $letter = getletter( 'claimissues', $letter ); - - # prepare the letter... - # search the biblionumber - $strsth = qq{ + } + : qq{ SELECT serial.*,subscription.*, biblio.*, aqbooksellers.* FROM serial LEFT JOIN subscription ON serial.subscriptionid=subscription.subscriptionid LEFT JOIN biblio ON serial.biblionumber=biblio.biblionumber LEFT JOIN aqbooksellers ON subscription.aqbooksellerid=aqbooksellers.id WHERE serial.serialid IN ( - } + } . join( ",", @$externalid ) . ")"; - } - - if ( $type eq 'claimacquisition' or $type eq 'claimissues' ) { my $sthorders = $dbh->prepare($strsth); $sthorders->execute; - my @fields = map { - $sthorders->{mysql_table}[$_] . "." . $sthorders->{NAME}[$_] } - (0 .. $#{$sthorders->{NAME}} ) ; - - my @orders_infos; - while ( my $row = $sthorders->fetchrow_arrayref() ) { - my %rec = (); - @rec{@fields} = @$row; - push @orders_infos, \%rec; + my $dataorders = $sthorders->fetchall_arrayref( {} ); + + my $sthbookseller = + $dbh->prepare("select * from aqbooksellers where id=?"); + $sthbookseller->execute( $dataorders->[0]->{booksellerid} ); + my $databookseller = $sthbookseller->fetchrow_hashref; + + my @email; + push @email, $databookseller->{bookselleremail} if $databookseller->{bookselleremail}; + push @email, $databookseller->{contemail} if $databookseller->{contemail}; + unless (@email) { + warn "Bookseller $dataorders->[0]->{booksellerid} without emails"; + return; } - # parsing branch info my $userenv = C4::Context->userenv; - parseletter( $letter, 'branches', $userenv->{branch} ); - - # parsing librarian name - $letter->{content} =~ s/<>/$userenv->{firstname}/g; - $letter->{content} =~ s/<>/$userenv->{surname}/g; - $letter->{content} =~ s/<>/$userenv->{emailaddress}/g; - - # Get Fields remplacement - my $order_format = $1 if ( $letter->{content} =~ m/(.*<\/order>)/xms ); - - # Foreach field to remplace - while ( $letter->{content} =~ m/<<([^>]*)>>/g ) { - my $field = $1; - my $value = $orders_infos[0]->{$field} || ""; - $value = sprintf("%.2f", $value) if $field =~ /price/; - $letter->{content} =~ s/<<$field>>/$value/g; - } - - if ( $order_format ) { - # For each order - foreach my $infos ( @orders_infos ) { - my $order_content = $order_format; - # We replace by value - while ( $order_content =~ m/<<([^>]*)>>/g ) { - my $field = $1; - my $value = $infos->{$field} || ""; - $value = sprintf("%.2f", $value) if $field =~ /price/; - $order_content =~ s/(<<$field>>)/$value/g; - } - $order_content =~ s/<\/{0,1}?order>//g; - $letter->{content} =~ s/.*<\/order>/$order_content\n$order_format/xms; - } - $letter->{content} =~ s/.*<\/order>//xms; - } - - my $innerletter = $letter; + my $letter = GetPreparedLetter ( + module => $type, + letter_code => $letter_code, + branchcode => $userenv->{branch}, + tables => { + 'branches' => $userenv->{branch}, + 'aqbooksellers' => $databookseller, + }, + repeat => $dataorders, + want_librarian => 1, + ) or return; # ... then send mail - if ( $orders_infos[0]->{'aqbooksellers.bookselleremail'} - || $orders_infos[0]->{'aqbooksellers.contemail'} ) { - my $to = $orders_infos[0]->{'aqbooksellers.bookselleremail'}; - $to .= ", " if $to; - $to .= $orders_infos[0]->{'aqbooksellers.contemail'} || ""; - my %mail = ( - To => $to, - From => $userenv->{emailaddress}, - Subject => Encode::encode( "utf8", "" . $innerletter->{title} ), - Message => Encode::encode( "utf8", "" . $innerletter->{content} ), - 'Content-Type' => 'text/plain; charset="utf8"', - ); - sendmail(%mail) or carp $Mail::Sendmail::error; - warn "sending to $mail{To} From $mail{From} subj $mail{Subject} Mess $mail{Message}" if $debug; - if ( C4::Context->preference("LetterLog") ) { - logaction( "ACQUISITION", "Send Acquisition claim letter", "", "order list : " . join( ",", @$externalid ) . "\n$innerletter->{title}\n$innerletter->{content}" ) if $type eq 'claimacquisition'; - logaction( "ACQUISITION", "CLAIM ISSUE", undef, "To=" . $mail{To} . " Title=" . $innerletter->{title} . " Content=" . $innerletter->{content} ) if $type eq 'claimissues'; - } - } else { - return {error => "no_email" }; - } - - warn "sending to From $userenv->{emailaddress} subj $innerletter->{title} Mess $innerletter->{content}" if $debug; - } + my %mail = ( + To => join( ','. @email), + From => $userenv->{emailaddress}, + Subject => "" . $letter->{title}, + Message => "" . $letter->{content}, + 'Content-Type' => 'text/plain; charset="utf8"', + ); + sendmail(%mail) or carp $Mail::Sendmail::error; - # send an "account details" notice to a newly created user + logaction( + "ACQUISITION", + $type eq 'claimissues' ? "CLAIM ISSUE" : "ACQUISITION CLAIM", + undef, + "To=" + . $databookseller->{contemail} + . " Title=" + . $letter->{title} + . " Content=" + . $letter->{content} + ) if C4::Context->preference("LetterLog"); + } + # send an "account details" notice to a newly created user elsif ( $type eq 'members' ) { - # must parse the password special, before it's hashed. - $letter->{content} =~ s/<>/$externalid->{'password'}/g; - - parseletter( $letter, 'borrowers', $externalid->{'borrowernumber'}); - parseletter( $letter, 'branches', $externalid->{'branchcode'} ); - my $branchdetails = GetBranchDetail($externalid->{'branchcode'}); + my $letter = GetPreparedLetter ( + module => 'members', + letter_code => $letter_code, + branchcode => $externalid->{'branchcode'}, + tables => { + 'branches' => $branchdetails, + 'borrowers' => $externalid->{'borrowernumber'}, + }, + substitute => { 'borrowers.password' => $externalid->{'password'} }, + want_librarian => 1, + ) or return; + my %mail = ( To => $externalid->{'emailaddr'}, From => $branchdetails->{'branchemail'} || C4::Context->preference("KohaAdminEmailAddress"), @@ -425,24 +403,148 @@ sub SendAlerts { } } -=head2 parseletter($letter, $table, $pk) - - 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) +=head2 GetPreparedLetter( %params ) + + %params hash: + module => letter module, mandatory + letter_code => letter code, mandatory + branchcode => for letter selection, if missing default system letter taken + tables => a hashref with table names as keys. Values are either: + - a scalar - primary key value + - an arrayref - primary key values + - a hashref - full record + substitute => custom substitution key/value pairs + repeat => records to be substituted on consecutive lines: + - an arrayref - tries to guess what needs substituting by + taking remaining << >> tokensr; not recommended + - a hashref token => @tables - replaces << >> << >> + subtemplate for each @tables row; table is a hashref as above + want_librarian => boolean, if set to true triggers librarian details + substitution from the userenv + Return value: + letter fields hashref (title & content useful) =cut -our %handles = (); -our %columns = (); +sub GetPreparedLetter { + my %params = @_; + + my $module = $params{module} or croak "No module"; + my $letter_code = $params{letter_code} or croak "No letter_code"; + my $branchcode = $params{branchcode} || ''; + + my $letter = getletter( $module, $letter_code, $branchcode ) + or warn( "No $module $letter_code letter"), + return; -sub parseletter_sth { + my $tables = $params{tables}; + my $substitute = $params{substitute}; + my $repeat = $params{repeat}; + $tables || $substitute || $repeat + or carp( "ERROR: nothing to substitute - both 'tables' and 'substitute' are empty" ), + return; + my $want_librarian = $params{want_librarian}; + + if ($substitute) { + while ( my ($token, $val) = each %$substitute ) { + $letter->{title} =~ s/<<$token>>/$val/g; + $letter->{content} =~ s/<<$token>>/$val/g; + } + } + + if ($want_librarian) { + # parsing librarian name + my $userenv = C4::Context->userenv; + $letter->{content} =~ s/<>/$userenv->{firstname}/go; + $letter->{content} =~ s/<>/$userenv->{surname}/go; + $letter->{content} =~ s/<>/$userenv->{emailaddress}/go; + } + + my ($repeat_no_enclosing_tags, $repeat_enclosing_tags); + + if ($repeat) { + if (ref ($repeat) eq 'ARRAY' ) { + $repeat_no_enclosing_tags = $repeat; + } else { + $repeat_enclosing_tags = $repeat; + } + } + + if ($repeat_enclosing_tags) { + while ( my ($tag, $tag_tables) = each %$repeat_enclosing_tags ) { + if ( $letter->{content} =~ m!<$tag>(.*)!s ) { + my $subcontent = $1; + my @lines = map { + my %subletter = ( title => '', content => $subcontent ); + _substitute_tables( \%subletter, $_ ); + $subletter{content}; + } @$tag_tables; + $letter->{content} =~ s!<$tag>.*!join( "\n", @lines )!se; + } + } + } + + if ($tables) { + _substitute_tables( $letter, $tables ); + } + + if ($repeat_no_enclosing_tags) { + if ( $letter->{content} =~ m/[^\n]*<<.*>>[^\n]*/so ) { + my $line = $&; + my $i = 1; + my @lines = map { + my $c = $line; + $c =~ s/<>/$i/go; + foreach my $field ( keys %{$_} ) { + $c =~ s/(<<[^\.]+.$field>>)/$_->{$field}/; + } + $i++; + $c; + } @$repeat_no_enclosing_tags; + + my $replaceby = join( "\n", @lines ); + $letter->{content} =~ s/\Q$line\E/$replaceby/s; + } + } + + $letter->{content} =~ s/<<\S*>>//go; #remove any stragglers +# $letter->{content} =~ s/<<[^>]*>>//go; + + return $letter; +} + +sub _substitute_tables { + my ( $letter, $tables ) = @_; + while ( my ($table, $param) = each %$tables ) { + next unless $param; + + my $ref = ref $param; + + my $values; + if ($ref && $ref eq 'HASH') { + $values = $param; + } + else { + my @pk; + my $sth = _parseletter_sth($table); + unless ($sth) { + warn "_parseletter_sth('$table') failed to return a valid sth. No substitution will be done for that table."; + return; + } + $sth->execute( $ref ? @$param : $param ); + + $values = $sth->fetchrow_hashref; + } + + _parseletter ( $letter, $table, $values ); + } +} + +my %handles = (); +sub _parseletter_sth { my $table = shift; unless ($table) { - carp "ERROR: parseletter_sth() called without argument (table)"; + carp "ERROR: _parseletter_sth() called without argument (table)"; return; } # check cache first @@ -456,9 +558,12 @@ sub parseletter_sth { ($table eq 'borrowers' ) ? "SELECT * FROM $table WHERE borrowernumber = ?" : ($table eq 'branches' ) ? "SELECT * FROM $table WHERE branchcode = ?" : ($table eq 'suggestions' ) ? "SELECT * FROM $table WHERE suggestionid = ?" : - ($table eq 'aqbooksellers') ? "SELECT * FROM $table WHERE id = ?" : undef ; + ($table eq 'aqbooksellers') ? "SELECT * FROM $table WHERE id = ?" : + ($table eq 'aqorders' ) ? "SELECT * FROM $table WHERE ordernumber = ?" : + ($table eq 'opac_news' ) ? "SELECT * FROM $table WHERE idnew = ?" : + undef ; unless ($query) { - warn "ERROR: No parseletter_sth query for table '$table'"; + warn "ERROR: No _parseletter_sth query for table '$table'"; return; # nothing to get } unless ($handles{$table} = C4::Context->dbh->prepare($query)) { @@ -468,25 +573,21 @@ sub parseletter_sth { return $handles{$table}; # now cache is populated for that $table } -sub parseletter { - my ( $letter, $table, $pk, $pk2 ) = @_; - unless ($letter) { - carp "ERROR: parseletter() 1st argument 'letter' empty"; - return; - } - my $sth = parseletter_sth($table); - unless ($sth) { - warn "parseletter_sth('$table') failed to return a valid sth. No substitution will be done for that table."; - return; - } - if ( $pk2 ) { - $sth->execute($pk, $pk2); - } else { - $sth->execute($pk); - } +=head2 _parseletter($letter, $table, $values) - my $values = $sth->fetchrow_hashref; - + parameters : + - $letter : a hash to letter fields (title & content useful) + - $table : the Koha table to parse. + - $values : table record hashref + parse all fields from a table, and replace values in title & content with the appropriate value + (not exported sub, used only internally) + +=cut + +my %columns = (); +sub _parseletter { + my ( $letter, $table, $values ) = @_; + # TEMPORARY hack until the expirationdate column is added to reserves if ( $table eq 'reserves' && $values->{'waitingdate'} ) { my @waitingdate = split /-/, $values->{'waitingdate'}; @@ -500,16 +601,51 @@ sub parseletter { )->output(); } + if ($letter->{content} && $letter->{content} =~ /<>/) { + my @da = localtime(); + my $todaysdate = "$da[2]:$da[1] " . C4::Dates->today(); + $letter->{content} =~ s/<>/$todaysdate/go; + } # and get all fields from the table - my $columns = C4::Context->dbh->prepare("SHOW COLUMNS FROM $table"); - $columns->execute; - while ( ( my $field ) = $columns->fetchrow_array ) { - my $replacefield = "<<$table.$field>>"; - $values->{$field} =~ s/\p{P}(?=$)//g if $values->{$field}; - my $replacedby = $values->{$field} || ''; - ($letter->{title} ) and $letter->{title} =~ s/$replacefield/$replacedby/g; - ($letter->{content}) and $letter->{content} =~ s/$replacefield/$replacedby/g; +# my $columns = $columns{$table}; +# unless ($columns) { +# $columns = $columns{$table} = C4::Context->dbh->selectcol_arrayref("SHOW COLUMNS FROM $table"); +# } +# foreach my $field (@$columns) { + + while ( my ($field, $val) = each %$values ) { + my $replacetablefield = "<<$table.$field>>"; + my $replacefield = "<<$field>>"; + $val =~ s/\p{P}(?=$)//g if $val; + my $replacedby = defined ($val) ? $val : ''; + ($letter->{title} ) and do { + $letter->{title} =~ s/$replacetablefield/$replacedby/g; + $letter->{title} =~ s/$replacefield/$replacedby/g; + }; + ($letter->{content}) and do { + $letter->{content} =~ s/$replacetablefield/$replacedby/g; + $letter->{content} =~ s/$replacefield/$replacedby/g; + }; + } + + if ($table eq 'borrowers' && $letter->{content}) { + if ( my $attributes = GetBorrowerAttributes($values->{borrowernumber}) ) { + my %attr; + foreach (@$attributes) { + my $code = $_->{code}; + my $val = $_->{value_description} || $_->{value}; + $val =~ s/\p{P}(?=$)//g if $val; + next unless $val gt ''; + $attr{$code} ||= []; + push @{ $attr{$code} }, $val; + } + while ( my ($code, $val_ar) = each %attr ) { + my $replacefield = "<>"; + my $replacedby = join ',', @$val_ar; + $letter->{content} =~ s/$replacefield/$replacedby/g; + } + } } return $letter; } @@ -694,31 +830,32 @@ returns your letter object, with the content updated. sub _add_attachments { my $params = shift; - return unless 'HASH' eq ref $params; - foreach my $required_parameter (qw( letter attachments message )) { - return unless exists $params->{$required_parameter}; - } - return $params->{'letter'} unless @{ $params->{'attachments'} }; + my $letter = $params->{'letter'}; + my $attachments = $params->{'attachments'}; + return $letter unless @$attachments; + my $message = $params->{'message'}; # First, we have to put the body in as the first attachment - $params->{'message'}->attach( - Type => 'TEXT', - Data => $params->{'letter'}->{'content'}, + $message->attach( + Type => $letter->{'content-type'} || 'TEXT', + Data => $letter->{'is_html'} + ? _wrap_html($letter->{'content'}, $letter->{'title'}) + : $letter->{'content'}, ); - foreach my $attachment ( @{ $params->{'attachments'} } ) { - $params->{'message'}->attach( + foreach my $attachment ( @$attachments ) { + $message->attach( Type => $attachment->{'type'}, Data => $attachment->{'content'}, Filename => $attachment->{'filename'}, ); } # we're forcing list context here to get the header, not the count back from grep. - ( $params->{'letter'}->{'content-type'} ) = grep( /^Content-Type:/, split( /\n/, $params->{'message'}->header_as_string ) ); - $params->{'letter'}->{'content-type'} =~ s/^Content-Type:\s+//; - $params->{'letter'}->{'content'} = $params->{'message'}->body_as_string; + ( $letter->{'content-type'} ) = grep( /^Content-Type:/, split( /\n/, $params->{'message'}->header_as_string ) ); + $letter->{'content-type'} =~ s/^Content-Type:\s+//; + $letter->{'content'} = $message->body_as_string; - return $params->{'letter'}; + return $letter; } @@ -785,14 +922,17 @@ sub _send_message_by_email ($;$$$) { my $utf8 = decode('MIME-Header', $message->{'subject'} ); $message->{subject}= encode('MIME-Header', $utf8); + my $subject = encode('utf8', $message->{'subject'}); my $content = encode('utf8', $message->{'content'}); + my $content_type = $message->{'content_type'} || 'text/plain; charset="UTF-8"'; + my $is_html = $content_type =~ m/html/io; my %sendmail_params = ( To => $to_address, From => $message->{'from_address'} || C4::Context->preference('KohaAdminEmailAddress'), - Subject => encode('utf8', $message->{'subject'}), + Subject => $subject, charset => 'utf8', - Message => $content, - 'content-type' => $message->{'content_type'} || 'text/plain; charset="UTF-8"', + Message => $is_html ? _wrap_html($content, $subject) : $content, + 'content-type' => $content_type, ); $sendmail_params{'Auth'} = {user => $username, pass => $password, method => $method} if $username; if ( my $bcc = C4::Context->preference('OverdueNoticeBcc') ) { @@ -812,6 +952,27 @@ sub _send_message_by_email ($;$$$) { } } +sub _wrap_html { + my ($content, $title) = @_; + + my $css = C4::Context->preference("NoticeCSS") || ''; + $css = qq{} if $css; + return < + + +$title + +$css + + +$content + + +EOS +} + sub _send_message_by_sms ($) { my $message = shift or return undef; my $member = C4::Members::GetMember( 'borrowernumber' => $message->{'borrowernumber'} ); diff --git a/C4/Members.pm b/C4/Members.pm index b81872c..7def77e 100644 --- a/C4/Members.pm +++ b/C4/Members.pm @@ -23,7 +23,7 @@ package C4::Members; use strict; #use warnings; FIXME - Bug 2505 use C4::Context; -use C4::Dates qw(format_date_in_iso); +use C4::Dates qw(format_date_in_iso format_date); use Digest::MD5 qw(md5_base64); use Date::Calc qw/Today Add_Delta_YM check_date Date_to_Days/; use C4::Log; # logaction @@ -31,8 +31,10 @@ use C4::Overdues; use C4::Reserves; use C4::Accounts; use C4::Biblio; +use C4::Letters; use C4::SQLHelper qw(InsertInTable UpdateInTable SearchInTable); use C4::Members::Attributes qw(SearchIdMatchingAttribute); +use C4::NewsChannels; #get slip news our ($VERSION, at ISA, at EXPORT, at EXPORT_OK,$debug); @@ -91,6 +93,8 @@ BEGIN { &DeleteMessage &GetMessages &GetMessagesCount + + &IssueSlip ); #Modify data @@ -2229,7 +2233,80 @@ sub DeleteMessage { logaction("MEMBERS", "DELCIRCMESSAGE", $message->{'borrowernumber'}, $message->{'message'}) if C4::Context->preference("BorrowersLog"); } -END { } # module clean-up code here (global destructor) +=head2 IssueSlip + + IssueSlip($branchcode, $borrowernumber, $quickslip) + + Returns letter hash ( see C4::Letters::GetPreparedLetter ) + + $quickslip is boolean, to indicate whether we want a quick slip + +=cut + +sub IssueSlip { + my ($branch, $borrowernumber, $quickslip) = @_; + +# return unless ( C4::Context->boolean_preference('printcirculationslips') ); + + my $today = POSIX::strftime("%Y-%m-%d", localtime); + + my $issueslist = GetPendingIssues($borrowernumber); + foreach my $it (@$issueslist){ + if ($it->{'issuedate'} eq $today) { + $it->{'today'} = 1; + } + elsif ($it->{'date_due'} le $today) { + $it->{'overdue'} = 1; + } + + $it->{'date_due'}=format_date($it->{'date_due'}); + } + my @issues = sort { $b->{'timestamp'} <=> $a->{'timestamp'} } @$issueslist; + + my ($letter_code, %repeat); + if ( $quickslip ) { + $letter_code = 'ISSUEQSLIP'; + %repeat = ( + 'checkedout' => [ map { + 'biblio' => $_, + 'items' => $_, + 'issues' => $_, + }, grep { $_->{'today'} } @issues ], + ); + } + else { + $letter_code = 'ISSUESLIP'; + %repeat = ( + 'checkedout' => [ map { + 'biblio' => $_, + 'items' => $_, + 'issues' => $_, + }, grep { !$_->{'overdue'} } @issues ], + + 'overdue' => [ map { + 'biblio' => $_, + 'items' => $_, + 'issues' => $_, + }, grep { $_->{'overdue'} } @issues ], + + 'news' => [ map { + $_->{'timestamp'} = $_->{'newdate'}; + { opac_news => $_ } + } @{ GetNewsToDisplay("slip") } ], + ); + } + + return C4::Letters::GetPreparedLetter ( + module => 'circulation', + letter_code => $letter_code, + branchcode => $branch, + tables => { + 'branches' => $branch, + 'borrowers' => $borrowernumber, + }, + repeat => \%repeat, + ); +} 1; diff --git a/C4/Members/Attributes.pm b/C4/Members/Attributes.pm index 4ae5600..33affa8 100644 --- a/C4/Members/Attributes.pm +++ b/C4/Members/Attributes.pm @@ -95,6 +95,24 @@ sub GetBorrowerAttributes { return \@results; } +=head2 GetAttributes + + my $attributes = C4::Members::Attributes::GetAttributes([$opac_only]); + +Retrieve an arrayref of extended attribute codes + +=cut + +sub GetAttributes { + my ($opac_only) = @_; + + my $dbh = C4::Context->dbh(); + my $query = "SELECT code FROM borrower_attribute_types"; + $query .= "\nWHERE opac_display = 1" if $opac_only; + $query .= "\nORDER BY code"; + return $dbh->selectcol_arrayref($query); +} + =head2 GetBorrowerAttributeValue my $value = C4::Members::Attributes::GetBorrowerAttributeValue($borrowernumber, $attribute_code); diff --git a/C4/Message.pm b/C4/Message.pm index 16272ff..4b88970 100644 --- a/C4/Message.pm +++ b/C4/Message.pm @@ -18,9 +18,15 @@ How to add a new message to the queue: use C4::Items; my $borrower = { borrowernumber => 1 }; my $item = C4::Items::GetItem(1); - my $letter = C4::Letters::getletter('circulation', 'CHECKOUT'); - C4::Letters::parseletter($letter, 'biblio', $item->{biblionumber}); - C4::Letters::parseletter($letter, 'biblioitems', $item->{biblionumber}); + my $letter = C4::Letters::GetPreparedLetter ( + module => 'circulation', + letter_code => 'CHECKOUT', + branchcode => $branch, + tables => { + 'biblio', $item->{biblionumber}, + 'biblioitems', $item->{biblionumber}, + }, + ); C4::Message->enqueue($letter, $borrower->{borrowernumber}, 'email'); How to update a borrower's last checkout message: diff --git a/C4/Print.pm b/C4/Print.pm index f810816..7fb55cf 100644 --- a/C4/Print.pm +++ b/C4/Print.pm @@ -20,8 +20,6 @@ package C4::Print; use strict; #use warnings; FIXME - Bug 2505 use C4::Context; -use C4::Members; -use C4::Dates qw(format_date); use vars qw($VERSION @ISA @EXPORT); @@ -30,7 +28,7 @@ BEGIN { $VERSION = 3.01; require Exporter; @ISA = qw(Exporter); - @EXPORT = qw(&remoteprint &printreserve &printslip); + @EXPORT = qw(&printslip); } =head1 NAME @@ -47,28 +45,48 @@ The functions in this module handle sending text to a printer. =head1 FUNCTIONS -=head2 remoteprint +=cut - &remoteprint($items, $borrower); +=comment + my $slip = <<"EOF"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Date: $todaysdate; -Prints the list of items in C<$items> to a printer. +ITEM RESERVED: +$itemdata->{'title'} ($itemdata->{'author'}) +barcode: $itemdata->{'barcode'} -C<$borrower> is a reference-to-hash giving information about a patron. -This may be gotten from C<&GetMemberDetails>. The patron's name -will be printed in the output. +COLLECT AT: $branchname + +BORROWER: +$bordata->{'surname'}, $bordata->{'firstname'} +card number: $bordata->{'cardnumber'} +Phone: $bordata->{'phone'} +$bordata->{'streetaddress'} +$bordata->{'suburb'} +$bordata->{'town'} +$bordata->{'emailaddress'} -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<&GetBorrowerIssues>. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +EOF =cut +=head2 printslip + + &printslip($slip) + +print a slip for the given $borrowernumber and $branchcode + +=cut + +sub printslip ($) { + my ($slip) = @_; + + return unless ( C4::Context->boolean_preference('printcirculationslips') ); + # FIXME - It'd be nifty if this could generate pretty PostScript. -sub remoteprint ($$) { - my ($items, $borrower) = @_; - (return) - unless ( C4::Context->boolean_preference('printcirculationslips') ); my $queue = ''; # FIXME - If 'queue' is undefined or empty, then presumably it should @@ -94,107 +112,13 @@ sub remoteprint ($$) { # print $queue; #open (FILE,">/tmp/$file"); - my $i = 0; - # FIXME - This is HLT-specific. Put this stuff in a customizable - # site-specific file somewhere. - print PRINTER "Horowhenua Library Trust\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 " " x 15; - print PRINTER "$itemdata->{'date_due'}\r\n"; - $i++; - } + print PRINTER $slip; print PRINTER "\r\n" x 7 ; close PRINTER; #system("lpr /tmp/$file"); } -sub printreserve { - - # FIXME - make useful - return; - - my ( $branchname, $bordata, $itemdata ) = @_; - my $printer = ''; - (return) unless ( C4::Context->boolean_preference('printreserveslips') ); - if ( $printer eq "" || $printer eq 'nulllp' ) { - open( PRINTER, ">>/tmp/kohares" ) - or die "Could not write to /tmp/kohares"; - } - else { - open( PRINTER, "| lpr -P $printer >/dev/null" ) - or die "Couldn't write to queue:$!\n"; - } - my @da = localtime(); - my $todaysdate = "$da[2]:$da[1] " . C4::Dates->today(); - 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; -} - -=head2 printslip - - &printslip($borrowernumber) - -print a slip for the given $borrowernumber - -=cut - -#' -sub printslip ($) { - - #FIXME - make useful - - my $borrowernumber = shift; - my $borrower = GetMemberDetails($borrowernumber); - my $issueslist = GetPendingIssues($borrowernumber); - foreach my $it (@$issueslist){ - $it->{'date_due'}=format_date($it->{'date_due'}); - } - my @issues = sort { $b->{'timestamp'} <=> $a->{'timestamp'} } @$issueslist; - remoteprint(\@issues, $borrower ); -} - -END { } # module clean-up code here (global destructor) - 1; __END__ diff --git a/C4/Reserves.pm b/C4/Reserves.pm index 359bbad..d2af1c5 100644 --- a/C4/Reserves.pm +++ b/C4/Reserves.pm @@ -121,6 +121,8 @@ BEGIN { &AlterPriority &ToggleLowestPriority + + &ReserveSlip ); @EXPORT_OK = qw( MergeHolds ); } @@ -194,32 +196,31 @@ sub AddReserve { # Send e-mail to librarian if syspref is active if(C4::Context->preference("emailLibrarianWhenHoldIsPlaced")){ my $borrower = C4::Members::GetMember(borrowernumber => $borrowernumber); - my $biblio = GetBiblioData($biblionumber); - my $letter = C4::Letters::getletter( 'reserves', 'HOLDPLACED'); - my $branchcode = $borrower->{branchcode}; - my $branch_details = C4::Branch::GetBranchDetail($branchcode); - my $admin_email_address =$branch_details->{'branchemail'} || C4::Context->preference('KohaAdminEmailAddress'); - - my %keys = (%$borrower, %$biblio); - foreach my $key (keys %keys) { - my $replacefield = "<<$key>>"; - $letter->{content} =~ s/$replacefield/$keys{$key}/g; - $letter->{title} =~ s/$replacefield/$keys{$key}/g; + my $branch_details = C4::Branch::GetBranchDetail($borrower->{branchcode}); + if ( my $letter = C4::Letters::GetPreparedLetter ( + module => 'reserves', + letter_code => 'HOLDPLACED', + branchcode => $branch, + tables => { + 'branches' => $branch_details, + 'borrowers' => $borrower, + 'biblio' => $biblionumber, + }, + ) ) { + + my $admin_email_address =$branch_details->{'branchemail'} || C4::Context->preference('KohaAdminEmailAddress'); + + C4::Letters::EnqueueLetter( + { letter => $letter, + borrowernumber => $borrowernumber, + message_transport_type => 'email', + from_address => $admin_email_address, + to_address => $admin_email_address, + } + ); } - - C4::Letters::EnqueueLetter( - { letter => $letter, - borrowernumber => $borrowernumber, - message_transport_type => 'email', - from_address => $admin_email_address, - to_address => $admin_email_address, - } - ); - - } - #} ($const eq "o" || $const eq "e") or return; # FIXME: why not have a useful return value? $query = qq/ @@ -1720,21 +1721,21 @@ sub _koha_notify_reserve { my $admin_email_address = $branch_details->{'branchemail'} || C4::Context->preference('KohaAdminEmailAddress'); - my $letter = getletter( 'reserves', $letter_code ); - die "Could not find a letter called '$letter_code' in the 'reserves' module" unless( $letter ); + my $letter = C4::Letters::GetPreparedLetter ( + module => 'reserves', + letter_code => $letter_code, + branchcode => $reserve->{branchcode}, + tables => { + 'branches' => $branch_details, + 'borrowers' => $borrower, + 'biblio' => $biblionumber, + 'reserves' => $reserve, + 'items', $reserve->{'itemnumber'}, + }, + substitute => { today => C4::Dates->new()->output() }, + ) or die "Could not find a letter called '$letter_code' in the 'reserves' module"; - C4::Letters::parseletter( $letter, 'branches', $reserve->{'branchcode'} ); - C4::Letters::parseletter( $letter, 'borrowers', $borrowernumber ); - C4::Letters::parseletter( $letter, 'biblio', $biblionumber ); - C4::Letters::parseletter( $letter, 'reserves', $borrowernumber, $biblionumber ); - if ( $reserve->{'itemnumber'} ) { - C4::Letters::parseletter( $letter, 'items', $reserve->{'itemnumber'} ); - } - my $today = C4::Dates->new()->output(); - $letter->{'title'} =~ s/<>/$today/g; - $letter->{'content'} =~ s/<>/$today/g; - $letter->{'content'} =~ s/<<[a-z0-9_]+\.[a-z0-9]+>>//g; #remove any stragglers if ( $print_mode ) { C4::Letters::EnqueueLetter( { @@ -1908,6 +1909,36 @@ sub MergeHolds { } +=head2 ReserveSlip + + ReserveSlip($branchcode, $borrowernumber, $biblionumber) + + Returns letter hash ( see C4::Letters::GetPreparedLetter ) or undef + +=cut + +sub ReserveSlip { + my ($branch, $borrowernumber, $biblionumber) = @_; + +# return unless ( C4::Context->boolean_preference('printreserveslips') ); + + my $reserve = GetReserveInfo($borrowernumber,$biblionumber ) + or return; + + return C4::Letters::GetPreparedLetter ( + module => 'circulation', + letter_code => 'RESERVESLIP', + branchcode => $branch, + tables => { + 'reserves' => $reserve, + 'branches' => $reserve->{branchcode}, + 'borrowers' => $reserve, + 'biblio' => $reserve, + 'items' => $reserve, + }, + ); +} + =head1 AUTHOR Koha Development Team diff --git a/C4/Suggestions.pm b/C4/Suggestions.pm index c9461f5..60d0e99 100644 --- a/C4/Suggestions.pm +++ b/C4/Suggestions.pm @@ -425,20 +425,24 @@ sub ModSuggestion { if ($suggestion->{STATUS}) { # fetch the entire updated suggestion so that we can populate the letter my $full_suggestion = GetSuggestion($suggestion->{suggestionid}); - my $letter = C4::Letters::getletter('suggestions', $full_suggestion->{STATUS}); - if ($letter) { - C4::Letters::parseletter($letter, 'branches', $full_suggestion->{branchcode}); - C4::Letters::parseletter($letter, 'borrowers', $full_suggestion->{suggestedby}); - C4::Letters::parseletter($letter, 'suggestions', $full_suggestion->{suggestionid}); - C4::Letters::parseletter($letter, 'biblio', $full_suggestion->{biblionumber}); - my $enqueued = C4::Letters::EnqueueLetter({ + if ( my $letter = C4::Letters::GetPreparedLetter ( + module => 'suggestions', + letter_code => $full_suggestion->{STATUS}, + branchcode => $full_suggestion->{branchcode}, + tables => { + 'branches' => $full_suggestion->{branchcode}, + 'borrowers' => $full_suggestion->{suggestedby}, + 'suggestions' => $full_suggestion, + 'biblio' => $full_suggestion->{biblionumber}, + }, + ) ) { + C4::Letters::EnqueueLetter({ letter => $letter, borrowernumber => $full_suggestion->{suggestedby}, suggestionid => $full_suggestion->{suggestionid}, LibraryName => C4::Context->preference("LibraryName"), message_transport_type => 'email', - }); - if (!$enqueued){warn "can't enqueue letter $letter";} + }) or warn "can't enqueue letter $letter"; } } return $status_update_table; diff --git a/acqui/booksellers.pl b/acqui/booksellers.pl index d7c64db..ac3c557 100755 --- a/acqui/booksellers.pl +++ b/acqui/booksellers.pl @@ -111,16 +111,11 @@ for my $vendor (@suppliers) { for my $basket ( @{$baskets} ) { my $authorisedby = $basket->{authorisedby}; - my $basketbranch = ''; # set a blank branch to start with - if ( GetMember( borrowernumber => $authorisedby ) ) { - # authorisedby may not be a valid borrowernumber; it's not foreign-key constrained! - $basketbranch = GetMember( borrowernumber => $authorisedby )->{branchcode}; - } if ($userenv->{'flags'} & 1 || #user is superlibrarian (haspermission( $uid, { acquisition => q{*} } ) && #user has acq permissions and ($viewbaskets eq 'all' || #user is allowed to see all baskets - ($viewbaskets eq 'branch' && $authorisedby && $userbranch eq $basketbranch) || #basket belongs to user's branch + ($viewbaskets eq 'branch' && $authorisedby && $userbranch eq GetMember( borrowernumber => $authorisedby )->{branchcode}) || #basket belongs to user's branch ($basket->{authorisedby} && $viewbaskets == 'user' && $authorisedby == $loggedinuser) #user created this basket ) ) diff --git a/circ/circulation.pl b/circ/circulation.pl index e8d22cb..6928966 100755 --- a/circ/circulation.pl +++ b/circ/circulation.pl @@ -24,7 +24,6 @@ use strict; #use warnings; FIXME - Bug 2505 use CGI; use C4::Output; -use C4::Print; use C4::Auth qw/:DEFAULT get_session/; use C4::Dates qw/format_date/; use C4::Branch; # GetBranches @@ -176,7 +175,7 @@ if ( $barcode eq '' && $query->param('charges') eq 'yes' ) { } if ( $print eq 'yes' && $borrowernumber ne '' ) { - printslip( $borrowernumber ); + PrintIssueSlip($session->param('branch') || $branch, $borrowernumber); $query->param( 'borrowernumber', '' ); $borrowernumber = ''; } diff --git a/circ/hold-transfer-slip.pl b/circ/hold-transfer-slip.pl index f581464..8ae5d2a 100755 --- a/circ/hold-transfer-slip.pl +++ b/circ/hold-transfer-slip.pl @@ -23,10 +23,8 @@ use strict; use C4::Context; use C4::Output; use CGI; -use C4::Auth; +use C4::Auth qw/:DEFAULT get_session/; use C4::Reserves; -use C4::Branch; -use C4::Dates qw/format_date format_date_in_iso/; use vars qw($debug); @@ -35,13 +33,16 @@ BEGIN { } my $input = new CGI; +my $sessionID = $input->cookie("CGISESSID"); +my $session = get_session($sessionID); + my $biblionumber = $input->param('biblionumber'); my $borrowernumber = $input->param('borrowernumber'); my $transfer = $input->param('transfer'); my ( $template, $loggedinuser, $cookie ) = get_template_and_user( { - template_name => "circ/hold-transfer-slip.tmpl", + template_name => "circ/printslip.tmpl", query => $input, type => "intranet", authnotrequired => 0, @@ -50,14 +51,21 @@ my ( $template, $loggedinuser, $cookie ) = get_template_and_user( } ); -my $reserveinfo = GetReserveInfo($borrowernumber,$biblionumber ); -my $pulldate = C4::Dates->new(); -$reserveinfo->{'pulldate'} = $pulldate->output(); -$reserveinfo->{'branchname'} = GetBranchName($reserveinfo->{'branchcode'}); -$reserveinfo->{'transferrequired'} = $transfer; - -$template->param( reservedata => [ $reserveinfo ] , - ); +my $userenv = C4::Context->userenv; +my ($slip, $is_html); +if ( my $letter = ReserveSlip ($session->param('branch') || $userenv->{branch}, $borrowernumber, $biblionumber) ) { + $slip = $letter->{content}; + $is_html = $letter->{is_html}; +} +else { + $slip = "Reserve not found"; +} +$template->param( + slip => $slip, + plain => !$is_html, + title => "Koha -- Circulation: Transfers", + stylesheet => C4::Context->preference("SlipCSS"), +); output_html_with_http_headers $input, $cookie, $template->output; diff --git a/installer/data/mysql/de-DE/mandatory/sample_notices.sql b/installer/data/mysql/de-DE/mandatory/sample_notices.sql index 0d172db..f668d99 100644 --- a/installer/data/mysql/de-DE/mandatory/sample_notices.sql +++ b/installer/data/mysql/de-DE/mandatory/sample_notices.sql @@ -11,7 +11,7 @@ VALUES ('circulation','ODUE','Mahnung','Mahnung','Liebe/r < ('reserves', 'HOLD_PRINT', 'Vormerkbenachrichtigung (Print)', 'Vormerkbenachrichtigung (Print)', '<>\r\n<>\r\n<>\r\n<>\r\n<> <>\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n<> <>\r\n<>\r\n<>\r\n<> <>\r\n<>\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nLiebe(r) <> <>,\r\n\r\nF??r Sie liegt seit dem <> eine Vormerkung zur Abholung bereit:\r\n\r\nTitel: <>\r\nVerfasser: <>\r\nSignatur: <>\r\n'), ('circulation','CHECKIN','R??ckgabequittung (Zusammenfassung)','R??ckgabequittung','Die folgenden Medien wurden zur??ckgegeben:\r\n----\r\n<>\r\n----\r\nVielen Dank.'), ('circulation','CHECKOUT','Ausleihquittung (Zusammenfassung)','Ausleihquittung','Die folgenden Medien wurden entliehen:\r\n----\r\n<>\r\n----\r\nVielen Dank f??r Ihren Besuch in <>.'), -('reserves', 'HOLDPLACED', 'Neue Vormerkung', 'Neue Vormerkung','Folgender Titel wurde vorgemerkt: <> (<<biblionumber>>) durch den Benutzer <<firstname>> <<surname>> (<<cardnumber>>).'), +('reserves', 'HOLDPLACED', 'Neue Vormerkung', 'Neue Vormerkung','Folgender Titel wurde vorgemerkt: <<biblio.title>> (<<biblio.biblionumber>>) durch den Benutzer <<borrowers.firstname>> <<borrowers.surname>> (<<borrowers.cardnumber>>).'), ('suggestions','ACCEPTED','Anschaffungsvorschlag wurde angenommen', 'Ihr Anschaffungsvorschlag wurde angenommen','Liebe(r) <<borrowers.firstname>> <<borrowers.surname>>,\n\nSie haben der Bibliothek folgendes Medium zur Anschaffung vorgeschlagen: <<suggestions.title>> by <<suggestions.author>>.\n\nDie Bibliothek hat diesen Titel heute recherchiert und wird Ihn sobald wie m??glich im Buchhandel bestellen. Sie erhalten Nachricht, sobald die Bestellung abgeschlossen ist und sobald der Titel in der Bibliotek verf??gbar ist.\n\nWenn Sie Fragen haben, richten Sie Ihre Mail bitte an: <<branches.branchemail>>.\n\nVielen Dank,\n\n<<branches.branchname>>'), ('suggestions','AVAILABLE','Vorgeschlagenes Medium verf??gbar', 'Das vorgeschlagene Medium ist jetzt verf??gbar','Liebe(r) <<borrowers.firstname>> <<borrowers.surname>>,\n\nSie haben der Bibliothek folgendes Medium zur Anschaffung vorgeschlagen: <<suggestions.title>> von <<suggestions.author>>.\n\nWir freuen uns Ihnen mitteilen zu k??nnen, dass dieser Titel jetzt im Bestand der Bibliothek verf??gbar ist.\n\nWenn Sie Fragen haben, richten Sie Ihre Mail bitte an: <<branches.branchemail>>.\n\nVielen Dank,\n\n<<branches.branchname>>'), ('suggestions','ORDERED','Vorgeschlagenes Medium bestellt', 'Das vorgeschlagene Medium wurde im Buchhandel bestellt','Liebe(r) <<borrowers.firstname>> <<borrowers.surname>>,\n\nSie haben der Bibliothek folgendes Medium zur Anschaffung vorgeschlaten: <<suggestions.title>> von <<suggestions.author>>.\n\nWir freuen uns Ihnen mitteilen zu k??nnen, dass dieser Titel jetzt im Buchhandel bestellt wurde. Nach Eintreffen wird er in unseren Bestand eingearbeitet.\n\nSie erhalten Nachricht, sobald das Medium verf??gbar ist.\n\nBei Nachfragen erreichen Sie uns unter der Emailadresse <<branches.branchemail>>.\n\nVielen Dank,\n\n<<branches.branchname>>'), diff --git a/installer/data/mysql/en/mandatory/sample_notices.sql b/installer/data/mysql/en/mandatory/sample_notices.sql index 5ca7eaf..a600373 100644 --- a/installer/data/mysql/en/mandatory/sample_notices.sql +++ b/installer/data/mysql/en/mandatory/sample_notices.sql @@ -11,8 +11,90 @@ VALUES ('circulation','ODUE','Overdue Notice','Item Overdue','Dear <<borrowers.f ('reserves', 'HOLD_PRINT', 'Hold Available for Pickup (print notice)', 'Hold Available for Pickup (print notice)', '<<branches.branchname>>\r\n<<branches.branchaddress1>>\r\n<<branches.branchaddress2>>\r\n\r\n\r\nChange Service Requested\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n<<borrowers.firstname>> <<borrowers.surname>>\r\n<<borrowers.address>>\r\n<<borrowers.city>> <<borrowers.zipcode>>\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n<<borrowers.firstname>> <<borrowers.surname>> <<borrowers.cardnumber>>\r\n\r\nYou have a hold available for pickup as of <<reserves.waitingdate>>:\r\n\r\nTitle: <<biblio.title>>\r\nAuthor: <<biblio.author>>\r\nCopy: <<items.copynumber>>\r\n'), ('circulation','CHECKIN','Item Check-in (Digest)','Check-ins','The following items have been checked in:\r\n----\r\n<<biblio.title>>\r\n----\r\nThank you.'), ('circulation','CHECKOUT','Item Check-out (Digest)','Checkouts','The following items have been checked out:\r\n----\r\n<<biblio.title>>\r\n----\r\nThank you for visiting <<branches.branchname>>.'), -('reserves', 'HOLDPLACED', 'Hold Placed on Item', 'Hold Placed on Item','A hold has been placed on the following item : <<title>> (<<biblionumber>>) by the user <<firstname>> <<surname>> (<<cardnumber>>).'), +('reserves', 'HOLDPLACED', 'Hold Placed on Item', 'Hold Placed on Item','A hold has been placed on the following item : <<biblio.title>> (<<biblio.biblionumber>>) by the user <<borrowers.firstname>> <<borrowers.surname>> (<<borrowers.cardnumber>>).'), ('suggestions','ACCEPTED','Suggestion accepted', 'Purchase suggestion accepted','Dear <<borrowers.firstname>> <<borrowers.surname>>,\n\nYou have suggested that the library acquire <<suggestions.title>> by <<suggestions.author>>.\n\nThe library has reviewed your suggestion today. The item will be ordered as soon as possible. You will be notified by mail when the order is completed, and again when the item arrives at the library.\n\nIf you have any questions, please email us at <<branches.branchemail>>.\n\nThank you,\n\n<<branches.branchname>>'), ('suggestions','AVAILABLE','Suggestion available', 'Suggested purchase available','Dear <<borrowers.firstname>> <<borrowers.surname>>,\n\nYou have suggested that the library acquire <<suggestions.title>> by <<suggestions.author>>.\n\nWe are pleased to inform you that the item you requested is now part of the collection.\n\nIf you have any questions, please email us at <<branches.branchemail>>.\n\nThank you,\n\n<<branches.branchname>>'), ('suggestions','ORDERED','Suggestion ordered', 'Suggested item ordered','Dear <<borrowers.firstname>> <<borrowers.surname>>,\n\nYou have suggested that the library acquire <<suggestions.title>> by <<suggestions.author>>.\n\nWe are pleased to inform you that the item you requested has now been ordered. It should arrive soon, at which time it will be processed for addition into the collection.\n\nYou will be notified again when the book is available.\n\nIf you have any questions, please email us at <<branches.branchemail>>\n\nThank you,\n\n<<branches.branchname>>'), ('suggestions','REJECTED','Suggestion rejected', 'Purchase suggestion declined','Dear <<borrowers.firstname>> <<borrowers.surname>>,\n\nYou have suggested that the library acquire <<suggestions.title>> by <<suggestions.author>>.\n\nThe library has reviewed your request today, and has decided not to accept the suggestion at this time.\n\nThe reason given is: <<suggestions.reason>>\n\nIf you have any questions, please email us at <<branches.branchemail>>.\n\nThank you,\n\n<<branches.branchname>>'); +INSERT INTO `letter` (module, code, name, title, content, is_html) +VALUES ('circulation','ISSUESLIP','Issue Slip','Issue Slip', '<h3><<branches.branchname>></h3> +Checked out to <<borrowers.title>> <<borrowers.firstname>> <<borrowers.initials>> <<borrowers.surname>> <br /> +(<<borrowers.cardnumber>>) <br /> + +<<today>><br /> + +<h4>Checked Out</h4> +<checkedout> +<p> +<<biblio.title>> <br /> +Barcode: <<items.barcode>><br /> +Date due: <<issues.date_due>><br /> +</p> +</checkedout> + +<h4>Overdues</h4> +<overdue> +<p> +<<biblio.title>> <br /> +Barcode: <<items.barcode>><br /> +Date due: <<issues.date_due>><br /> +</p> +</overdue> + +<hr> + +<h4 style="text-align: center; font-style:italic;">News</h4> +<news> +<div class="newsitem"> +<h5 style="margin-bottom: 1px; margin-top: 1px"><b><<opac_news.title>></b></h5> +<p style="margin-bottom: 1px; margin-top: 1px"><<opac_news.new>></p> +<p class="newsfooter" style="font-size: 8pt; font-style:italic; margin-bottom: 1px; margin-top: 1px">Posted on <<opac_news.timestamp>></p> +<hr /> +</div> +</news>', 1), +('circulation','ISSUEQSLIP','Issue Quick Slip','Issue Quick Slip', '<h3><<branches.branchname>></h3> +Checked out to <<borrowers.title>> <<borrowers.firstname>> <<borrowers.initials>> <<borrowers.surname>> <br /> +(<<borrowers.cardnumber>>) <br /> + +<<today>><br /> + +<h4>Checked Out Today</h4> +<checkedout> +<p> +<<biblio.title>> <br /> +Barcode: <<items.barcode>><br /> +Date due: <<issues.date_due>><br /> +</p> +</checkedout>', 1), +('circulation','RESERVESLIP','Reserve Slip','Reserve Slip', '<h5>Date: <<today>></h5> + +<h3> Transfer to/Hold in <<branches.branchname>></h3> + +<reserves> +<div> +<h3><<borrowers.surname>>, <<borrowers.firstname>></h3> + +<ul> + <li><<borrowers.cardnumber>></li> + <li><<borrowers.phone>></li> + <li> <<borrowers.address>><br /> + <<borrowers.address2>><br /> + <<borrowers.city >> <<borrowers.zipcode>> + </li> + <li><<borrowers.email>></li> +</ul> +<br /> +<h3>ITEM ON HOLD</h3> + <h4><<biblio.title>></h4> + <h5><<biblio.author>></h5> + <ul> + <li><<items.barcode>></li> + <li><<items.itemcallnumber>></li> + <li><<reserves.waitingdate>></li> + </ul> + <p>Notes: + <pre><<reserves.reservenotes>></pre> + </p> +</div> +</reserves>', 1); + diff --git a/installer/data/mysql/es-ES/mandatory/sample_notices.sql b/installer/data/mysql/es-ES/mandatory/sample_notices.sql index 78b80fa..0450bd0 100644 --- a/installer/data/mysql/es-ES/mandatory/sample_notices.sql +++ b/installer/data/mysql/es-ES/mandatory/sample_notices.sql @@ -11,7 +11,7 @@ VALUES ('circulation','ODUE','Overdue Notice','Item Overdue','Dear <<borrowers.f ('reserves', 'HOLD_PRINT', 'Hold Available for Pickup (print notice)', 'Hold Available for Pickup (print notice)', '<<branches.branchname>>\r\n<<branches.branchaddress1>>\r\n<<branches.branchaddress2>>\r\n\r\n\r\nChange Service Requested\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n<<borrowers.firstname>> <<borrowers.surname>>\r\n<<borrowers.address>>\r\n<<borrowers.city>> <<borrowers.zipcode>>\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n<<borrowers.firstname>> <<borrowers.surname>> <<borrowers.cardnumber>>\r\n\r\nYou have a hold available for pickup as of <<reserves.waitingdate>>:\r\n\r\nTitle: <<biblio.title>>\r\nAuthor: <<biblio.author>>\r\nCopy: <<items.copynumber>>\r\n'), ('circulation','CHECKIN','Item Check-in (Digest)','Check-ins','The following items have been checked in:\r\n----\r\n<<biblio.title>>\r\n----\r\nThank you.'), ('circulation','CHECKOUT','Item Check-out (Digest)','Checkouts','The following items have been checked out:\r\n----\r\n<<biblio.title>>\r\n----\r\nThank you for visiting <<branches.branchname>>.'), -('reserves', 'HOLDPLACED', 'Hold Placed on Item', 'Hold Placed on Item','A hold has been placed on the following item : <<title>> (<<biblionumber>>) by the user <<firstname>> <<surname>> (<<cardnumber>>).'), +('reserves', 'HOLDPLACED', 'Hold Placed on Item', 'Hold Placed on Item','A hold has been placed on the following item : <<biblio.title>> (<<biblio.biblionumber>>) by the user <<borrowers.firstname>> <<borrowers.surname>> (<<borrowers.cardnumber>>).'), ('suggestions','ACCEPTED','Suggestion accepted', 'Purchase suggestion accepted','Dear <<borrowers.firstname>> <<borrowers.surname>>,\n\nYou have suggested that the library acquire <<suggestions.title>> by <<suggestions.author>>.\n\nThe library has reviewed your suggestion today. The item will be ordered as soon as possible. You will be notified by mail when the order is completed, and again when the item arrives at the library.\n\nIf you have any questions, please email us at <<branches.branchemail>>.\n\nThank you,\n\n<<branches.branchname>>'), ('suggestions','AVAILABLE','Suggestion available', 'Suggested purchase available','Dear <<borrowers.firstname>> <<borrowers.surname>>,\n\nYou have suggested that the library acquire <<suggestions.title>> by <<suggestions.author>>.\n\nWe are pleased to inform you that the item you requested is now part of the collection.\n\nIf you have any questions, please email us at <<branches.branchemail>>.\n\nThank you,\n\n<<branches.branchname>>'), ('suggestions','ORDERED','Suggestion ordered', 'Suggested item ordered','Dear <<borrowers.firstname>> <<borrowers.surname>>,\n\nYou have suggested that the library acquire <<suggestions.title>> by <<suggestions.author>>.\n\nWe are pleased to inform you that the item you requested has now been ordered. It should arrive soon, at which time it will be processed for addition into the collection.\n\nYou will be notified again when the book is available.\n\nIf you have any questions, please email us at <<branches.branchemail>>\n\nThank you,\n\n<<branches.branchname>>'), diff --git a/installer/data/mysql/fr-FR/1-Obligatoire/sample_notices.sql b/installer/data/mysql/fr-FR/1-Obligatoire/sample_notices.sql index 9e9f66d..4eb1210 100644 --- a/installer/data/mysql/fr-FR/1-Obligatoire/sample_notices.sql +++ b/installer/data/mysql/fr-FR/1-Obligatoire/sample_notices.sql @@ -13,7 +13,7 @@ VALUES ('reserves', 'HOLD_PRINT', 'Hold Available for Pickup (print notice)', 'Hold Available for Pickup at <<branches.branchname>>', '<<branches.branchname>>\n<<branches.branchaddress1>>\n<<branches.branchaddress2>>\n\n\nChange Service Requested\n\n\n\n\n\n\n\n<<borrowers.firstname>> <<borrowers.surname>>\n<<borrowers.address>>\n<<borrowers.city>> <<borrowers.zipcode>>\n\n\n\n\n\n\n\n\n\n\n<<borrowers.firstname>> <<borrowers.surname>> <<borrowers.cardnumber>>\n\nYou have a hold available for pickup as of <<reserves.waitingdate>>:\r\n\r\nTitle: <<biblio.title>>\r\nAuthor: <<biblio.author>>\r\nCopy: <<items.copynumber>>\r\n'), ('circulation','CHECKIN','Item Check-in (Digest)','Check-ins','The following items have been checked in:\r\n----\r\n<<biblio.title>>\r\n----\r\nThank you.'), ('circulation','CHECKOUT','Item Check-out (Digest)','Checkouts','The following items have been checked out:\r\n----\r\n<<biblio.title>>\r\n----\r\nThank you for visiting <<branches.branchname>>.'), -('reserves', 'HOLDPLACED', 'Hold Placed on Item', 'Hold Placed on Item','A hold has been placed on the following item : <<title>> (<<biblionumber>>) by the user <<firstname>> <<surname>> (<<cardnumber>>).'), +('reserves', 'HOLDPLACED', 'Hold Placed on Item', 'Hold Placed on Item','A hold has been placed on the following item : <<biblio.title>> (<<biblio.biblionumber>>) by the user <<borrowers.firstname>> <<borrowers.surname>> (<<borrowers.cardnumber>>).'), ('suggestions','ACCEPTED','Suggestion accepted', 'Purchase suggestion accepted','Dear <<borrowers.firstname>> <<borrowers.surname>>,\n\nYou have suggested that the library acquire <<suggestions.title>> by <<suggestions.author>>.\n\nThe library has reviewed your suggestion today. The item will be ordered as soon as possible. You will be notified by mail when the order is completed, and again when the item arrives at the library.\n\nIf you have any questions, please email us at <<branches.branchemail>>.\n\nThank you,\n\n<<branches.branchname>>'), ('suggestions','AVAILABLE','Suggestion available', 'Suggested purchase available','Dear <<borrowers.firstname>> <<borrowers.surname>>,\n\nYou have suggested that the library acquire <<suggestions.title>> by <<suggestions.author>>.\n\nWe are pleased to inform you that the item you requested is now part of the collection.\n\nIf you have any questions, please email us at <<branches.branchemail>>.\n\nThank you,\n\n<<branches.branchname>>'), ('suggestions','ORDERED','Suggestion ordered', 'Suggested item ordered','Dear <<borrowers.firstname>> <<borrowers.surname>>,\n\nYou have suggested that the library acquire <<suggestions.title>> by <<suggestions.author>>.\n\nWe are pleased to inform you that the item you requested has now been ordered. It should arrive soon, at which time it will be processed for addition into the collection.\n\nYou will be notified again when the book is available.\n\nIf you have any questions, please email us at <<branches.branchemail>>\n\nThank you,\n\n<<branches.branchname>>'), diff --git a/installer/data/mysql/it-IT/necessari/notices.sql b/installer/data/mysql/it-IT/necessari/notices.sql index 78b80fa..0450bd0 100644 --- a/installer/data/mysql/it-IT/necessari/notices.sql +++ b/installer/data/mysql/it-IT/necessari/notices.sql @@ -11,7 +11,7 @@ VALUES ('circulation','ODUE','Overdue Notice','Item Overdue','Dear <<borrowers.f ('reserves', 'HOLD_PRINT', 'Hold Available for Pickup (print notice)', 'Hold Available for Pickup (print notice)', '<<branches.branchname>>\r\n<<branches.branchaddress1>>\r\n<<branches.branchaddress2>>\r\n\r\n\r\nChange Service Requested\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n<<borrowers.firstname>> <<borrowers.surname>>\r\n<<borrowers.address>>\r\n<<borrowers.city>> <<borrowers.zipcode>>\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n<<borrowers.firstname>> <<borrowers.surname>> <<borrowers.cardnumber>>\r\n\r\nYou have a hold available for pickup as of <<reserves.waitingdate>>:\r\n\r\nTitle: <<biblio.title>>\r\nAuthor: <<biblio.author>>\r\nCopy: <<items.copynumber>>\r\n'), ('circulation','CHECKIN','Item Check-in (Digest)','Check-ins','The following items have been checked in:\r\n----\r\n<<biblio.title>>\r\n----\r\nThank you.'), ('circulation','CHECKOUT','Item Check-out (Digest)','Checkouts','The following items have been checked out:\r\n----\r\n<<biblio.title>>\r\n----\r\nThank you for visiting <<branches.branchname>>.'), -('reserves', 'HOLDPLACED', 'Hold Placed on Item', 'Hold Placed on Item','A hold has been placed on the following item : <<title>> (<<biblionumber>>) by the user <<firstname>> <<surname>> (<<cardnumber>>).'), +('reserves', 'HOLDPLACED', 'Hold Placed on Item', 'Hold Placed on Item','A hold has been placed on the following item : <<biblio.title>> (<<biblio.biblionumber>>) by the user <<borrowers.firstname>> <<borrowers.surname>> (<<borrowers.cardnumber>>).'), ('suggestions','ACCEPTED','Suggestion accepted', 'Purchase suggestion accepted','Dear <<borrowers.firstname>> <<borrowers.surname>>,\n\nYou have suggested that the library acquire <<suggestions.title>> by <<suggestions.author>>.\n\nThe library has reviewed your suggestion today. The item will be ordered as soon as possible. You will be notified by mail when the order is completed, and again when the item arrives at the library.\n\nIf you have any questions, please email us at <<branches.branchemail>>.\n\nThank you,\n\n<<branches.branchname>>'), ('suggestions','AVAILABLE','Suggestion available', 'Suggested purchase available','Dear <<borrowers.firstname>> <<borrowers.surname>>,\n\nYou have suggested that the library acquire <<suggestions.title>> by <<suggestions.author>>.\n\nWe are pleased to inform you that the item you requested is now part of the collection.\n\nIf you have any questions, please email us at <<branches.branchemail>>.\n\nThank you,\n\n<<branches.branchname>>'), ('suggestions','ORDERED','Suggestion ordered', 'Suggested item ordered','Dear <<borrowers.firstname>> <<borrowers.surname>>,\n\nYou have suggested that the library acquire <<suggestions.title>> by <<suggestions.author>>.\n\nWe are pleased to inform you that the item you requested has now been ordered. It should arrive soon, at which time it will be processed for addition into the collection.\n\nYou will be notified again when the book is available.\n\nIf you have any questions, please email us at <<branches.branchemail>>\n\nThank you,\n\n<<branches.branchname>>'), diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql index 67149c9..0cff8c5 100644 --- a/installer/data/mysql/kohastructure.sql +++ b/installer/data/mysql/kohastructure.sql @@ -1169,10 +1169,12 @@ DROP TABLE IF EXISTS `letter`; CREATE TABLE `letter` ( -- table for all notice templates in Koha `module` varchar(20) NOT NULL default '', -- Koha module that triggers this notice `code` varchar(20) NOT NULL default '', -- unique identifier for this notice + `branchcode` varchar(10) default NULL, -- foreign key, linking to the branches table for the location the item was checked out `name` varchar(100) NOT NULL default '', -- plain text name for this notice + `is_html` tinyint(1) default 0, `title` varchar(200) NOT NULL default '', -- subject line of the notice `content` text, -- body text for the notice - PRIMARY KEY (`module`,`code`) + PRIMARY KEY (`module`,`code`, `branchcode`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- @@ -2253,12 +2255,13 @@ CREATE TABLE `message_transports` ( `is_digest` tinyint(1) NOT NULL default '0', `letter_module` varchar(20) NOT NULL default '', `letter_code` varchar(20) NOT NULL default '', + `branchcode` varchar(10) NOT NULL default '', PRIMARY KEY (`message_attribute_id`,`message_transport_type`,`is_digest`), KEY `message_transport_type` (`message_transport_type`), KEY `letter_module` (`letter_module`,`letter_code`), CONSTRAINT `message_transports_ibfk_1` FOREIGN KEY (`message_attribute_id`) REFERENCES `message_attributes` (`message_attribute_id`) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT `message_transports_ibfk_2` FOREIGN KEY (`message_transport_type`) REFERENCES `message_transport_types` (`message_transport_type`) ON DELETE CASCADE ON UPDATE CASCADE, - CONSTRAINT `message_transports_ibfk_3` FOREIGN KEY (`letter_module`, `letter_code`) REFERENCES `letter` (`module`, `code`) ON DELETE CASCADE ON UPDATE CASCADE + CONSTRAINT `message_transports_ibfk_3` FOREIGN KEY (`letter_module`, `letter_code`, `branchcode`) REFERENCES `letter` (`module`, `code`, `branchcode`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- diff --git a/installer/data/mysql/nb-NO/1-Obligatorisk/sample_notices.sql b/installer/data/mysql/nb-NO/1-Obligatorisk/sample_notices.sql index 762da91..f40da36 100644 --- a/installer/data/mysql/nb-NO/1-Obligatorisk/sample_notices.sql +++ b/installer/data/mysql/nb-NO/1-Obligatorisk/sample_notices.sql @@ -32,7 +32,7 @@ VALUES ('circulation','ODUE','Purring','Purring p?? dokument','<<borrowers.first ('reserves', 'HOLD_PRINT', 'Hentemelding (p?? papir)', 'Hentemelding', '<<branches.branchname>>\r\n<<branches.branchaddress1>>\r\n<<branches.branchaddress2>>\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n<<borrowers.firstname>> <<borrowers.surname>>\r\n<<borrowers.address>>\r\n<<borrowers.city>> <<borrowers.zipcode>>\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n<<borrowers.firstname>> <<borrowers.surname>> <<borrowers.cardnumber>>\r\n\r\nDu har et reservert dokument som kan hentes fra <<reserves.waitingdate>>:\r\n\r\nTittel: <<biblio.title>>\r\nForfatter: <<biblio.author>>\r\nEksemplar: <<items.copynumber>>\r\n'), ('circulation','CHECKIN','Innlevering','Melding om innlevering','F??lgende dokument har blitt innlevert:\r\n----\r\n<<biblio.title>>\r\n----\r\nVennlig hilsen\r\nBiblioteket'), ('circulation','CHECKOUT','Utl??n','Melding om utl??n','F??lgende dokument har blitt l??nt ut:\r\n----\r\n<<biblio.title>>\r\n----\r\nVennlig hilsen\r\nBiblioteket'), -('reserves', 'HOLDPLACED', 'Melding om reservasjon', 'Melding om reservasjon','F??lgende dokument har blitt reservert : <<title>> (<<biblionumber>>) av <<firstname>> <<surname>> (<<cardnumber>>).'), +('reserves', 'HOLDPLACED', 'Melding om reservasjon', 'Melding om reservasjon','F??lgende dokument har blitt reservert : <<biblio.title>> (<<biblio.biblionumber>>) av <<borrowers.firstname>> <<borrowers.surname>> (<<borrowers.cardnumber>>).'), ('suggestions','ACCEPTED','Forslag godtatt', 'Innkj??psforslag godtatt','<<borrowers.firstname>> <<borrowers.surname>>,\n\nDu har foresl??tt at biblioteket kj??per inn <<suggestions.title>> av <<suggestions.author>>.\n\nBiblioteket har vurdert forslaget i dag. Dokumentet vil bli bestilt s?? fort det lar seg gj??re. Du vil f?? en ny melding n??r bestillingen er gjort, og n??r dokumentet ankommer biblioteket.\n\nEr det noe du lurer p??, vennligst kontakt oss p?? <<branches.branchemail>>.\n\nVennlig hilsen,\n\n<<branches.branchname>>'), ('suggestions','AVAILABLE','Foresl??tt dokument tilgjengelig', 'Foresl??tt dokument tilgjengelig','<<borrowers.firstname>> <<borrowers.surname>>,\n\nDu har foresl??tt at biblioteket kj??per inn <<suggestions.title>> av <<suggestions.author>>.\n\nVi har gleden av ?? informere deg om at dokumentet n?? er innlemmet i samlingen.\n\nEr det noe du lurer p??, vennligst kontakt oss p?? <<branches.branchemail>>.\n\nVennlig hilsen,\n\n<<branches.branchname>>'), ('suggestions','ORDERED','Innkj??psforslag i bestilling', 'Innkj??psforslag i bestilling','Dear <<borrowers.firstname>> <<borrowers.surname>>,\n\nDu har foresl??tt at biblioteket kj??per inn <<suggestions.title>> av <<suggestions.author>>.\n\nVi har gleden av ?? informere deg om at dokumentet du foreslo n?? er i bestilling.\n\nDu vil f?? en ny melding n??r dokumentet er tilgjengelig.\n\nEr det noe du lurer p??, vennligst kontakt oss p?? <<branches.branchemail>>.\n\nVennlig hilsen,\n\n<<branches.branchname>>'), diff --git a/installer/data/mysql/pl-PL/mandatory/sample_notices.sql b/installer/data/mysql/pl-PL/mandatory/sample_notices.sql index c101b0b..73102af 100644 --- a/installer/data/mysql/pl-PL/mandatory/sample_notices.sql +++ b/installer/data/mysql/pl-PL/mandatory/sample_notices.sql @@ -13,7 +13,7 @@ VALUES ('reserves', 'HOLD_PRINT', 'Hold Available for Pickup (print notice)', 'Hold Available for Pickup (print notice)', '<<branches.branchname>>\r\n<<branches.branchaddress1>>\r\n<<branches.branchaddress2>>\r\n\r\n\r\nChange Service Requested\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n<<borrowers.firstname>> <<borrowers.surname>>\r\n<<borrowers.address>>\r\n<<borrowers.city>> <<borrowers.zipcode>>\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n<<borrowers.firstname>> <<borrowers.surname>> <<borrowers.cardnumber>>\r\n\r\nYou have a hold available for pickup as of <<reserves.waitingdate>>:\r\n\r\nTitle: <<biblio.title>>\r\nAuthor: <<biblio.author>>\r\nCopy: <<items.copynumber>>\r\n'), ('circulation','CHECKIN','Item Check-in (Digest)','Check-ins','The following items have been checked in:\r\n----\r\n<<biblio.title>>\r\n----\r\nThank you.'), ('circulation','CHECKOUT','Item Check-out (Digest)','Checkouts','The following items have been checked out:\r\n----\r\n<<biblio.title>>\r\n----\r\nThank you for visiting <<branches.branchname>>.'), -('reserves', 'HOLDPLACED', 'Hold Placed on Item', 'Hold Placed on Item','A hold has been placed on the following item : <<title>> (<<biblionumber>>) by the user <<firstname>> <<surname>> (<<cardnumber>>).'), +('reserves', 'HOLDPLACED', 'Hold Placed on Item', 'Hold Placed on Item','A hold has been placed on the following item : <<biblio.title>> (<<biblio.biblionumber>>) by the user <<borrowers.firstname>> <<borrowers.surname>> (<<borrowers.cardnumber>>).'), ('suggestions','ACCEPTED','Suggestion accepted', 'Purchase suggestion accepted','Dear <<borrowers.firstname>> <<borrowers.surname>>,\n\nYou have suggested that the library acquire <<suggestions.title>> by <<suggestions.author>>.\n\nThe library has reviewed your suggestion today. The item will be ordered as soon as possible. You will be notified by mail when the order is completed, and again when the item arrives at the library.\n\nIf you have any questions, please email us at <<branches.branchemail>>.\n\nThank you,\n\n<<branches.branchname>>'), ('suggestions','AVAILABLE','Suggestion available', 'Suggested purchase available','Dear <<borrowers.firstname>> <<borrowers.surname>>,\n\nYou have suggested that the library acquire <<suggestions.title>> by <<suggestions.author>>.\n\nWe are pleased to inform you that the item you requested is now part of the collection.\n\nIf you have any questions, please email us at <<branches.branchemail>>.\n\nThank you,\n\n<<branches.branchname>>'), ('suggestions','ORDERED','Suggestion ordered', 'Suggested item ordered','Dear <<borrowers.firstname>> <<borrowers.surname>>,\n\nYou have suggested that the library acquire <<suggestions.title>> by <<suggestions.author>>.\n\nWe are pleased to inform you that the item you requested has now been ordered. It should arrive soon, at which time it will be processed for addition into the collection.\n\nYou will be notified again when the book is available.\n\nIf you have any questions, please email us at <<branches.branchemail>>\n\nThank you,\n\n<<branches.branchname>>'), diff --git a/installer/data/mysql/ru-RU/mandatory/sample_notices.sql b/installer/data/mysql/ru-RU/mandatory/sample_notices.sql index 5ca7eaf..e13782a 100644 --- a/installer/data/mysql/ru-RU/mandatory/sample_notices.sql +++ b/installer/data/mysql/ru-RU/mandatory/sample_notices.sql @@ -11,7 +11,7 @@ VALUES ('circulation','ODUE','Overdue Notice','Item Overdue','Dear <<borrowers.f ('reserves', 'HOLD_PRINT', 'Hold Available for Pickup (print notice)', 'Hold Available for Pickup (print notice)', '<<branches.branchname>>\r\n<<branches.branchaddress1>>\r\n<<branches.branchaddress2>>\r\n\r\n\r\nChange Service Requested\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n<<borrowers.firstname>> <<borrowers.surname>>\r\n<<borrowers.address>>\r\n<<borrowers.city>> <<borrowers.zipcode>>\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n<<borrowers.firstname>> <<borrowers.surname>> <<borrowers.cardnumber>>\r\n\r\nYou have a hold available for pickup as of <<reserves.waitingdate>>:\r\n\r\nTitle: <<biblio.title>>\r\nAuthor: <<biblio.author>>\r\nCopy: <<items.copynumber>>\r\n'), ('circulation','CHECKIN','Item Check-in (Digest)','Check-ins','The following items have been checked in:\r\n----\r\n<<biblio.title>>\r\n----\r\nThank you.'), ('circulation','CHECKOUT','Item Check-out (Digest)','Checkouts','The following items have been checked out:\r\n----\r\n<<biblio.title>>\r\n----\r\nThank you for visiting <<branches.branchname>>.'), -('reserves', 'HOLDPLACED', 'Hold Placed on Item', 'Hold Placed on Item','A hold has been placed on the following item : <<title>> (<<biblionumber>>) by the user <<firstname>> <<surname>> (<<cardnumber>>).'), +('reserves', 'HOLDPLACED', 'Hold Placed on Item', 'Hold Placed on Item','A hold has been placed on the following item : <<biblio.title>> (<<biblio.biblionumber>>) by the user <<borrowers.firstname>> <<borrowers.surname>> (<<borrowers.cardnumber>>).'), ('suggestions','ACCEPTED','Suggestion accepted', 'Purchase suggestion accepted','Dear <<borrowers.firstname>> <<borrowers.surname>>,\n\nYou have suggested that the library acquire <<suggestions.title>> by <<suggestions.author>>.\n\nThe library has reviewed your suggestion today. The item will be ordered as soon as possible. You will be notified by mail when the order is completed, and again when the item arrives at the library.\n\nIf you have any questions, please email us at <<branches.branchemail>>.\n\nThank you,\n\n<<branches.branchname>>'), ('suggestions','AVAILABLE','Suggestion available', 'Suggested purchase available','Dear <<borrowers.firstname>> <<borrowers.surname>>,\n\nYou have suggested that the library acquire <<suggestions.title>> by <<suggestions.author>>.\n\nWe are pleased to inform you that the item you requested is now part of the collection.\n\nIf you have any questions, please email us at <<branches.branchemail>>.\n\nThank you,\n\n<<branches.branchname>>'), ('suggestions','ORDERED','Suggestion ordered', 'Suggested item ordered','Dear <<borrowers.firstname>> <<borrowers.surname>>,\n\nYou have suggested that the library acquire <<suggestions.title>> by <<suggestions.author>>.\n\nWe are pleased to inform you that the item you requested has now been ordered. It should arrive soon, at which time it will be processed for addition into the collection.\n\nYou will be notified again when the book is available.\n\nIf you have any questions, please email us at <<branches.branchemail>>\n\nThank you,\n\n<<branches.branchname>>'), diff --git a/installer/data/mysql/sysprefs.sql b/installer/data/mysql/sysprefs.sql index 0cc79b2..1d0513b 100644 --- a/installer/data/mysql/sysprefs.sql +++ b/installer/data/mysql/sysprefs.sql @@ -330,6 +330,8 @@ INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('EasyAnalyticalRecords','0','If on, display in the catalogue screens tools to easily setup analytical record relationships','','YesNo'); INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('OpacShowRecentComments',0,'If ON a link to recent comments will appear in the OPAC masthead',NULL,'YesNo'); INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ('CircAutoPrintQuickSlip', '1', 'Choose what should happen when an empty barcode field is submitted in circulation: Display a print quick slip window or Clear the screen.',NULL,'YesNo'); +INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('NoticeCSS','','Notices CSS url.',NULL,'free'); +INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('SlipCSS','','Slips CSS url.',NULL,'free'); INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES ('OPACLocalCoverImages','0','Display local cover images on OPAC search and details pages.','1','YesNo'); INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES ('LocalCoverImages','0','Display local cover images on intranet details pages.','1','YesNo'); INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES ('AllowMultipleCovers','0','Allow multiple cover images to be attached to each bibliographic record.','1','YesNo'); diff --git a/installer/data/mysql/uk-UA/mandatory/sample_notices.sql b/installer/data/mysql/uk-UA/mandatory/sample_notices.sql index 6ab0e18..a908f6c 100644 --- a/installer/data/mysql/uk-UA/mandatory/sample_notices.sql +++ b/installer/data/mysql/uk-UA/mandatory/sample_notices.sql @@ -10,7 +10,7 @@ VALUES ('circulation','ODUE','Overdue Notice','Item Overdue','Dear <<borrowers.f ('reserves', 'HOLD', 'Hold Available for Pickup', 'Hold Available for Pickup at <<branches.branchname>>', 'Dear <<borrowers.firstname>> <<borrowers.surname>>,\r\n\r\nYou have a hold available for pickup as of <<reserves.waitingdate>>:\r\n\r\nTitle: <<biblio.title>>\r\nAuthor: <<biblio.author>>\r\nCopy: <<items.copynumber>>\r\nLocation: <<branches.branchname>>\r\n<<branches.branchaddress1>>\r\n<<branches.branchaddress2>>\r\n<<branches.branchaddress3>>\r\n<<branches.branchcity>> <<branches.branchzip>>'), ('circulation','CHECKIN','Item Check-in (Digest)','Check-ins','The following items have been checked in:\r\n----\r\n<<biblio.title>>\r\n----\r\nThank you.'), ('circulation','CHECKOUT','Item Check-out (Digest)','Checkouts','The following items have been checked out:\r\n----\r\n<<biblio.title>>\r\n----\r\nThank you for visiting <<branches.branchname>>.'), -('reserves', 'HOLDPLACED', 'Hold Placed on Item', 'Hold Placed on Item','A hold has been placed on the following item : <<title>> (<<biblionumber>>) by the user <<firstname>> <<surname>> (<<cardnumber>>).'), +('reserves', 'HOLDPLACED', 'Hold Placed on Item', 'Hold Placed on Item','A hold has been placed on the following item : <<biblio.title>> (<<biblio.biblionumber>>) by the user <<borrowers.firstname>> <<borrowers.surname>> (<<borrowers.cardnumber>>).'), ('suggestions','ACCEPTED','Suggestion accepted', 'Purchase suggestion accepted','Dear <<borrowers.firstname>> <<borrowers.surname>>,\n\nYou have suggested that the library acquire <<suggestions.title>> by <<suggestions.author>>.\n\nThe library has reviewed your suggestion today. The item will be ordered as soon as possible. You will be notified by mail when the order is completed, and again when the item arrives at the library.\n\nIf you have any questions, please email us at <<branches.branchemail>>.\n\nThank you,\n\n<<branches.branchname>>'), ('suggestions','AVAILABLE','Suggestion available', 'Suggested purchase available','Dear <<borrowers.firstname>> <<borrowers.surname>>,\n\nYou have suggested that the library acquire <<suggestions.title>> by <<suggestions.author>>.\n\nWe are pleased to inform you that the item you requested is now part of the collection.\n\nIf you have any questions, please email us at <<branches.branchemail>>.\n\nThank you,\n\n<<branches.branchname>>'), ('suggestions','ORDERED','Suggestion ordered', 'Suggested item ordered','Dear <<borrowers.firstname>> <<borrowers.surname>>,\n\nYou have suggested that the library acquire <<suggestions.title>> by <<suggestions.author>>.\n\nWe are pleased to inform you that the item you requested has now been ordered. It should arrive soon, at which time it will be processed for addition into the collection.\n\nYou will be notified again when the book is available.\n\nIf you have any questions, please email us at <<branches.branchemail>>\n\nThank you,\n\n<<branches.branchname>>'), diff --git a/installer/data/mysql/updatedatabase.pl b/installer/data/mysql/updatedatabase.pl index d2d9d97..cc6c06a 100755 --- a/installer/data/mysql/updatedatabase.pl +++ b/installer/data/mysql/updatedatabase.pl @@ -4497,7 +4497,6 @@ if (C4::Context->preference("Version") < TransformToNum($DBversion)) { print "Upgrade to $DBversion done (Add 461 subfield 9 to default framework)\n"; SetVersion ($DBversion); } - } $DBversion = "3.05.00.018"; @@ -4712,6 +4711,105 @@ if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) { SetVersion($DBversion); } +$DBversion = "3.07.00.XXX"; +if (C4::Context->preference("Version") < TransformToNum($DBversion)) { + $dbh->do("ALTER TABLE `message_transports` DROP FOREIGN KEY `message_transports_ibfk_3`"); + $dbh->do("ALTER TABLE `letter` DROP PRIMARY KEY"); + $dbh->do("ALTER TABLE `letter` ADD `branchcode` varchar(10) default NULL AFTER `code`"); + $dbh->do("ALTER TABLE `letter` ADD PRIMARY KEY (`module`,`code`, `branchcode`)"); + $dbh->do("ALTER TABLE `message_transports` ADD `branchcode` varchar(10) NOT NULL default ''"); + $dbh->do("ALTER TABLE `message_transports` ADD CONSTRAINT `message_transports_ibfk_3` FOREIGN KEY (`letter_module`, `letter_code`, `branchcode`) REFERENCES `letter` (`module`, `code`, `branchcode`) ON DELETE CASCADE ON UPDATE CASCADE"); + $dbh->do("ALTER TABLE `letter` ADD `is_html` tinyint(1) default 0 AFTER `name`"); + + $dbh->do("INSERT INTO `letter` (module, code, name, title, content, is_html) + VALUES ('circulation','ISSUESLIP','Issue Slip','Issue Slip', '<h3><<branches.branchname>></h3> +Checked out to <<borrowers.title>> <<borrowers.firstname>> <<borrowers.initials>> <<borrowers.surname>> <br /> +(<<borrowers.cardnumber>>) <br /> + +<<today>><br /> + +<h4>Checked Out</h4> +<checkedout> +<p> +<<biblio.title>> <br /> +Barcode: <<items.barcode>><br /> +Date due: <<issues.date_due>><br /> +</p> +</checkedout> + +<h4>Overdues</h4> +<overdue> +<p> +<<biblio.title>> <br /> +Barcode: <<items.barcode>><br /> +Date due: <<issues.date_due>><br /> +</p> +</overdue> + +<hr> + +<h4 style=\"text-align: center; font-style:italic;\">News</h4> +<news> +<div class=\"newsitem\"> +<h5 style=\"margin-bottom: 1px; margin-top: 1px\"><b><<opac_news.title>></b></h5> +<p style=\"margin-bottom: 1px; margin-top: 1px\"><<opac_news.new>></p> +<p class=\"newsfooter\" style=\"font-size: 8pt; font-style:italic; margin-bottom: 1px; margin-top: 1px\">Posted on <<opac_news.timestamp>></p> +<hr /> +</div> +</news>', 1)"); + $dbh->do("INSERT INTO `letter` (module, code, name, title, content, is_html) + VALUES ('circulation','ISSUEQSLIP','Issue Quick Slip','Issue Quick Slip', '<h3><<branches.branchname>></h3> +Checked out to <<borrowers.title>> <<borrowers.firstname>> <<borrowers.initials>> <<borrowers.surname>> <br /> +(<<borrowers.cardnumber>>) <br /> + +<<today>><br /> + +<h4>Checked Out Today</h4> +<checkedout> +<p> +<<biblio.title>> <br /> +Barcode: <<items.barcode>><br /> +Date due: <<issues.date_due>><br /> +</p> +</checkedout>', 1)"); + $dbh->do("INSERT INTO `letter` (module, code, name, title, content, is_html) + VALUES ('circulation','RESERVESLIP','Reserve Slip','Reserve Slip', '<h5>Date: <<today>></h5> + +<h3> Transfer to/Hold in <<branches.branchname>></h3> + +<h3><<borrowers.surname>>, <<borrowers.firstname>></h3> + +<ul> + <li><<borrowers.cardnumber>></li> + <li><<borrowers.phone>></li> + <li> <<borrowers.address>><br /> + <<borrowers.address2>><br /> + <<borrowers.city >> <<borrowers.zipcode>> + </li> + <li><<borrowers.email>></li> +</ul> +<br /> +<h3>ITEM ON HOLD</h3> +<h4><<biblio.title>></h4> +<h5><<biblio.author>></h5> +<ul> + <li><<items.barcode>></li> + <li><<items.itemcallnumber>></li> + <li><<reserves.waitingdate>></li> +</ul> +<p>Notes: +<pre><<reserves.reservenotes>></pre> +</p>', 1)"); + + $dbh->do("INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('NoticeCSS','','Notices CSS url.',NULL,'free')"); + $dbh->do("INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('SlipCSS','','Slips CSS url.',NULL,'free')"); + + $dbh->do("UPDATE `letter` SET content = replace(content, '<<title>>', '<<biblio.title>>') WHERE code = 'HOLDPLACED'"); + + print "Upgrade to $DBversion done (Add branchcode and is_html to letter table; Default ISSUESLIP and RESERVESLIP letters; Add NoticeCSS and SlipCSS sysprefs)\n"; + SetVersion($DBversion); +} + =head1 FUNCTIONS =head2 DropAllForeignKeys($table) diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/circ-toolbar.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/circ-toolbar.inc index a4acfdf..4e583f1 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/circ-toolbar.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/circ-toolbar.inc @@ -42,8 +42,10 @@ function update_child() { }); // YUI Toolbar Functions + var slip_re = /slip/; function printx_window(print_type) { - window.open("/cgi-bin/koha/members/moremember.pl?borrowernumber=[% borrowernumber %]&print=" + print_type, "printwindow"); + var handler = print_type.match(slip_re) ? "printslip" : "moremember"; + window.open("/cgi-bin/koha/members/" + handler + ".pl?borrowernumber=[% borrowernumber %]&print=" + print_type, "printwindow"); return false; } function searchToHold(){ diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref index b3716c0..1556385 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref @@ -98,6 +98,11 @@ Circulation: yes: "open a print quick slip window" no: "clear the screen" - . + - + - Include the stylesheet at + - pref: NoticeCSS + class: url + - on Notices. (This should be a complete URL, starting with <code>http://</code>) Checkout Policy: - - pref: AllowNotForLoanOverride diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/staff_client.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/staff_client.pref index df0a434..efa33a8 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/staff_client.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/staff_client.pref @@ -83,6 +83,11 @@ Staff Client: Results: "Results page (for future use, Results XSLT not functional at this time)." Both: "Both Results and Details pages (for future use, Results XSLT not functional at this time)." - 'Note: The corresponding XSLT option must be turned on.' + - + - Include the stylesheet at + - pref: SlipCSS + class: url + - on Issue and Reserve Slips. (This should be a complete URL, starting with <code>http://</code>.) Options: - - pref: viewMARC diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/batch/print-notices.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/batch/print-notices.tt index 1904381..73f9e61 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/batch/print-notices.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/batch/print-notices.tt @@ -8,11 +8,7 @@ --> </style> [% IF ( stylesheet ) %] - <style type="text/css"> - <!-- - [% stylesheet %] - --> - </style> + <link rel="stylesheet" type="text/css" href="[% stylesheet %]"> [% END %] </head> <body> diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/hold-transfer-slip.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/hold-transfer-slip.tt deleted file mode 100644 index 18d45aa..0000000 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/hold-transfer-slip.tt +++ /dev/null @@ -1,54 +0,0 @@ -[% INCLUDE 'doc-head-open.inc' %] -<title>Koha -- Circulation: Transfers -[% INCLUDE 'doc-head-close-receipt.inc' %] - - -
    - -[% FOREACH reservedat IN reservedata %] - -
    Date: [% reservedat.pulldate %]
    -

    [% IF ( reservedat.transferrequired ) %]Transfer to [% reservedat.branchname %] [% ELSE %]Hold in [% reservedat.branchname %][% END %]

    - -
    - -

    [% reservedat.surname %], [% reservedat.firstname %]

    - -
      -
    • [% reservedat.cardnumber %]
    • - [% IF ( reservedat.phone ) %] -
    • [% reservedat.phone %]
    • - [% END %] -
    • - [% reservedat.address %]
      - [% IF ( reservedat.address2 ) %][% reservedat.address2 %]
      [% END %] - [% reservedat.city %] [% reservedat.zip %] -
    • - [% IF ( reservedat.email ) %] -
    • [% reservedat.email %]
    • - [% END %] -
    -
    -

    ITEM ON HOLD

    -

    [% reservedat.title |html %]

    -
    [% reservedat.author %]
    -
      - [% IF ( reservedat.barcode ) %]
    • [% reservedat.barcode %]
    • [% END %] - [% IF ( reservedat.itemcallnumber ) %]
    • [% reservedat.itemcallnumber %]
    • [% END %] - [% IF ( reservedat.waitingdate ) %]
    • [% reservedat.waitingdate %]
    • [% END %] -
    - [% IF ( reservedat.reservenotes ) %] -

    Notes: [% reservedat.reservenotes %]

    - [% END %] - - - -[% END %] -
    -[% INCLUDE 'intranet-bottom.inc' %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/printslip.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/printslip.tt new file mode 100644 index 0000000..a790069 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/printslip.tt @@ -0,0 +1,28 @@ +[% INCLUDE 'doc-head-open.inc' %] +[% title %] + + + +[% IF stylesheet %] + +[% END %] + + + + +
    + +[% IF plain %] +
    +[% slip %]
    +
    +[% ELSE %] +[% slip %] +[% END %] + +[% INCLUDE 'intranet-bottom.inc' %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/letter.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/letter.tt index 063236e..eec2384 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/letter.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/letter.tt @@ -5,14 +5,29 @@ -
    - +[% IF ( no_op_set ) %] +
    + + [% UNLESS independant_branch %] +

    + Select a library : + +

    + [% END %] +

    + + +

    +
    + [% IF ( search ) %]

    You Searched for [% searchfield %]

    [% END %] - [% IF ( letter ) %] + [% IF ( letter && !independant_branch) %] + [% select_for_copy = BLOCK %] + + [% END %] + [% END %] +
    + + - [% FOREACH lette IN letter %] - [% UNLESS ( loop.odd ) %] + + [% FOREACH lette IN letter %] + [% can_edit = lette.branchcode || !independant_branch %] + [% UNLESS ( loop.odd ) %] - [% ELSE %] + [% ELSE %] - [% END %] + [% END %] + + - [% END %] + [% END %] +
    Branch Module Code Name     
    [% lette.branchname || "(All libraries)" %] [% lette.module %] [% lette.code %] [% lette.name %] - Edit + [% IF can_edit %] + Edit + [% END %] + + [% IF !independant_branch || !lette.branchcode %] +
    + + + + + [% IF independant_branch %] + + [% ELSE %] + [% select_for_copy %] + [% END %] + +
    + [% END %]
    - [% IF ( lette.protected ) %] - - - [% ELSE %] - Delete - [% END %] + [% IF !lette.protected && can_edit %] + Delete + [% END %]
    - [% END %] +[% END %] - [% END %] - [% IF ( add_form ) %] +[% IF ( add_form ) %] -
    - + + [% IF ( modify ) %] @@ -182,6 +229,20 @@ $(document).ready(function() {
    [% IF ( modify ) %]Modify notice[% ELSE %]Add notice[% END %]
      + + [% IF independant_branch %] + + [% ELSE %] +
    1. + + +
    2. + [% END %]
    3. @@ -235,6 +296,14 @@ $(document).ready(function() {
    4. + + [% IF is_html %] + + [% ELSE %] + + [% END %] +
    5. +
    6. @@ -252,27 +321,31 @@ $(document).ready(function() {
    +
    +
    - [% END %] +[% END %] - [% IF ( add_validate ) %] +[% IF ( add_validate ) %] Data recorded
    - [% END %] +[% END %] - [% IF ( delete_confirm ) %] +[% IF ( delete_confirm ) %]

    Delete Notice?

    + + @@ -280,6 +353,7 @@ $(document).ready(function() {
    Branch Module Code Name
    [% branchname %] [% module %] [% code %] [% name %]
    + @@ -290,14 +364,14 @@ $(document).ready(function() {
    - [% END %] +[% END %] - [% IF ( delete_confirmed ) %] +[% IF ( delete_confirmed ) %] Data deleted
    - [% END %] +[% END %]
    diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt index b71a1ee..5cc3bbf 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt @@ -26,7 +26,7 @@ [% END %] [% IF ( CAN_user_tools_edit_notices ) %] -
    Notices
    +
    Notices & Slips
    Define notices (print and email notification messages for overdues, etc.)
    [% END %] diff --git a/members/memberentry.pl b/members/memberentry.pl index 86dd6ed..c474a66 100755 --- a/members/memberentry.pl +++ b/members/memberentry.pl @@ -347,10 +347,7 @@ if ((!$nok) and $nodouble and ($op eq 'insert' or $op eq 'save')){ # if we manage to find a valid email address, send notice if ($emailaddr) { $newdata{emailaddr} = $emailaddr; - my $letter = getletter ('members', "ACCTDETAILS:$newdata{'branchcode'}") ; - # if $branch notice fails, then email a default notice instead. - $letter = getletter ('members', "ACCTDETAILS") if !$letter; - SendAlerts ( 'members' , \%newdata , $letter ) if $letter + SendAlerts ( 'members', \%newdata, "ACCTDETAILS" ); } } diff --git a/members/moremember.pl b/members/moremember.pl index c477100..5a988f9 100755 --- a/members/moremember.pl +++ b/members/moremember.pl @@ -51,7 +51,6 @@ use C4::Reserves; use C4::Branch; # GetBranchName use C4::Overdues qw/CheckBorrowerDebarred/; use C4::Form::MessagingPreferences; -use C4::NewsChannels; #get slip news use List::MoreUtils qw/uniq/; use C4::Members::Attributes qw(GetBorrowerAttributes); @@ -484,13 +483,4 @@ $template->param( activeBorrowerRelationship => (C4::Context->preference('borrowerRelationship') ne ''), ); -#Get the slip news items -my $all_koha_news = &GetNewsToDisplay("slip"); -my $koha_news_count = scalar @$all_koha_news; - -$template->param( - koha_news => $all_koha_news, - koha_news_count => $koha_news_count -); - output_html_with_http_headers $input, $cookie, $template->output; diff --git a/members/printslip.pl b/members/printslip.pl new file mode 100755 index 0000000..3a499cd --- /dev/null +++ b/members/printslip.pl @@ -0,0 +1,92 @@ +#!/usr/bin/perl + +# Copyright 2000-2002 Katipo Communications +# Copyright 2010 BibLibre +# +# 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +=head1 moremember.pl + + script to do a borrower enquiry/bring up borrower details etc + Displays all the details about a borrower + written 20/12/99 by chris at katipo.co.nz + last modified 21/1/2000 by chris at katipo.co.nz + modified 31/1/2001 by chris at katipo.co.nz + to not allow items on request to be renewed + + needs html removed and to use the C4::Output more, but its tricky + +=cut + +use strict; +#use warnings; FIXME - Bug 2505 +use CGI; +use C4::Context; +use C4::Auth qw/:DEFAULT get_session/; +use C4::Output; +use C4::Members; +use C4::Koha; + +#use Smart::Comments; +#use Data::Dumper; + +use vars qw($debug); + +BEGIN { + $debug = $ENV{DEBUG} || 0; +} + +my $input = new CGI; +my $sessionID = $input->cookie("CGISESSID"); +my $session = get_session($sessionID); + +$debug or $debug = $input->param('debug') || 0; +my $print = $input->param('print'); +my $error = $input->param('error'); + +# circ staff who process checkouts but can't edit +# patrons still need to be able to print receipts +my $flagsrequired = { circulate => "circulate_remaining_permissions" }; + +my ( $template, $loggedinuser, $cookie ) = get_template_and_user( + { + template_name => "circ/printslip.tmpl", + query => $input, + type => "intranet", + authnotrequired => 0, + flagsrequired => $flagsrequired, + debug => 1, + } +); + +my $borrowernumber = $input->param('borrowernumber'); +my $branch=C4::Context->userenv->{'branch'}; +my ($slip, $is_html); +if (my $letter = IssueSlip ($session->param('branch') || $branch, $borrowernumber, $print eq "qslip")) { + $slip = $letter->{content}; + $is_html = $letter->{is_html}; +} + +$template->param( + slip => $slip, + plain => !$is_html, + title => "Print Receipt for $borrowernumber", + stylesheet => C4::Context->preference("SlipCSS"), + error => $error, +); + +output_html_with_http_headers $input, $cookie, $template->output; diff --git a/misc/cronjobs/advance_notices.pl b/misc/cronjobs/advance_notices.pl index 1fa358f..09c4017 100755 --- a/misc/cronjobs/advance_notices.pl +++ b/misc/cronjobs/advance_notices.pl @@ -79,13 +79,10 @@ patrons. It queues them in the message queue, which is processed by the process_message_queue.pl cronjob. See the comments in the script for directions on changing the script. This script has the following parameters : - -c Confirm and remove this help & warning - -m maximum number of days in advance to send advance notices. - -n send No mail. Instead, all mail messages are printed on screen. Usefull for testing purposes. - -v verbose - -i csv list of fields that get substituted into templates in places - of the EEitems.contentEE placeholder. Defaults to - issuedate,title,barcode,author + -c Confirm and remove this help & warning + -m maximum number of days in advance to send advance notices. + -n send No mail. Instead, all mail messages are printed on screen. Usefull for testing purposes. + -v verbose ENDUSAGE # Since advance notice options are not visible in the web-interface @@ -157,8 +154,6 @@ UPCOMINGITEM: foreach my $upcoming ( @$upcoming_dues ) { } else { my $biblio = C4::Biblio::GetBiblioFromItemNumber( $upcoming->{'itemnumber'} ); my $letter_type = 'DUE'; - $letter = C4::Letters::getletter( 'circulation', $letter_type ); - die "no letter of type '$letter_type' found. Please see sample_notices.sql" unless $letter; $sth->execute($upcoming->{'borrowernumber'},$upcoming->{'itemnumber'},'0'); my $titles = ""; while ( my $item_info = $sth->fetchrow_hashref()) { @@ -166,13 +161,14 @@ UPCOMINGITEM: foreach my $upcoming ( @$upcoming_dues ) { $titles .= join("\t", at item_info) . "\n"; } - $letter = parse_letter( { letter => $letter, + $letter = parse_letter( { letter_code => $letter_type, borrowernumber => $upcoming->{'borrowernumber'}, branchcode => $upcoming->{'branchcode'}, biblionumber => $biblio->{'biblionumber'}, itemnumber => $upcoming->{'itemnumber'}, substitute => { 'items.content' => $titles } - } ); + } ) + or die "no letter of type '$letter_type' found. Please see sample_notices.sql"; } } else { $borrower_preferences = C4::Members::Messaging::GetMessagingPreferences( { borrowernumber => $upcoming->{'borrowernumber'}, @@ -189,8 +185,6 @@ UPCOMINGITEM: foreach my $upcoming ( @$upcoming_dues ) { } else { my $biblio = C4::Biblio::GetBiblioFromItemNumber( $upcoming->{'itemnumber'} ); my $letter_type = 'PREDUE'; - $letter = C4::Letters::getletter( 'circulation', $letter_type ); - die "no letter of type '$letter_type' found. Please see sample_notices.sql" unless $letter; $sth->execute($upcoming->{'borrowernumber'},$upcoming->{'itemnumber'},$borrower_preferences->{'days_in_advance'}); my $titles = ""; while ( my $item_info = $sth->fetchrow_hashref()) { @@ -198,13 +192,14 @@ UPCOMINGITEM: foreach my $upcoming ( @$upcoming_dues ) { $titles .= join("\t", at item_info) . "\n"; } - $letter = parse_letter( { letter => $letter, + $letter = parse_letter( { letter_code => $letter_type, borrowernumber => $upcoming->{'borrowernumber'}, branchcode => $upcoming->{'branchcode'}, biblionumber => $biblio->{'biblionumber'}, itemnumber => $upcoming->{'itemnumber'}, substitute => { 'items.content' => $titles } - } ); + } ) + or die "no letter of type '$letter_type' found. Please see sample_notices.sql"; } } @@ -250,8 +245,6 @@ PATRON: while ( my ( $borrowernumber, $digest ) = each %$upcoming_digest ) { my $letter_type = 'PREDUEDGST'; - my $letter = C4::Letters::getletter( 'circulation', $letter_type ); - die "no letter of type '$letter_type' found. Please see sample_notices.sql" unless $letter; $sth->execute($borrowernumber,$borrower_preferences->{'days_in_advance'}); my $titles = ""; @@ -259,12 +252,13 @@ PATRON: while ( my ( $borrowernumber, $digest ) = each %$upcoming_digest ) { my @item_info = map { $_ =~ /^date|date$/ ? format_date($item_info->{$_}) : $item_info->{$_} || '' } @item_content_fields; $titles .= join("\t", at item_info) . "\n"; } - $letter = parse_letter( { letter => $letter, + my $letter = parse_letter( { letter_code => $letter_type, borrowernumber => $borrowernumber, substitute => { count => $count, 'items.content' => $titles } - } ); + } ) + or die "no letter of type '$letter_type' found. Please see sample_notices.sql"; if ($nomail) { local $, = "\f"; print $letter->{'content'}; @@ -290,20 +284,19 @@ PATRON: while ( my ( $borrowernumber, $digest ) = each %$due_digest ) { next PATRON unless $borrower_preferences; # how could this happen? my $letter_type = 'DUEDGST'; - my $letter = C4::Letters::getletter( 'circulation', $letter_type ); - die "no letter of type '$letter_type' found. Please see sample_notices.sql" unless $letter; $sth->execute($borrowernumber,'0'); my $titles = ""; while ( my $item_info = $sth->fetchrow_hashref()) { my @item_info = map { $_ =~ /^date|date$/ ? format_date($item_info->{$_}) : $item_info->{$_} || '' } @item_content_fields; $titles .= join("\t", at item_info) . "\n"; } - $letter = parse_letter( { letter => $letter, + my $letter = parse_letter( { letter_code => $letter_type, borrowernumber => $borrowernumber, substitute => { count => $count, 'items.content' => $titles } - } ); + } ) + or die "no letter of type '$letter_type' found. Please see sample_notices.sql"; if ($nomail) { local $, = "\f"; @@ -323,40 +316,35 @@ PATRON: while ( my ( $borrowernumber, $digest ) = each %$due_digest ) { =head2 parse_letter - - =cut sub parse_letter { my $params = shift; - foreach my $required ( qw( letter borrowernumber ) ) { + foreach my $required ( qw( letter_code borrowernumber ) ) { return unless exists $params->{$required}; } - if ( $params->{'substitute'} ) { - while ( my ($key, $replacedby) = each %{$params->{'substitute'}} ) { - my $replacefield = "<<$key>>"; - - $params->{'letter'}->{title} =~ s/$replacefield/$replacedby/g; - $params->{'letter'}->{content} =~ s/$replacefield/$replacedby/g; - } - } - - C4::Letters::parseletter( $params->{'letter'}, 'borrowers', $params->{'borrowernumber'} ); + my %table_params = ( 'borrowers' => $params->{'borrowernumber'} ); - if ( $params->{'branchcode'} ) { - C4::Letters::parseletter( $params->{'letter'}, 'branches', $params->{'branchcode'} ); + if ( my $p = $params->{'branchcode'} ) { + $table_params{'branches'} = $p; } - if ( $params->{'itemnumber'} ) { - C4::Letters::parseletter( $params->{'letter'}, 'issues', $params->{'itemnumber'} ); - C4::Letters::parseletter( $params->{'letter'}, 'items', $params->{'itemnumber'} ); + if ( my $p = $params->{'itemnumber'} ) { + $table_params{'issues'} = $p; + $table_params{'items'} = $p; } - if ( $params->{'biblionumber'} ) { - C4::Letters::parseletter( $params->{'letter'}, 'biblio', $params->{'biblionumber'} ); - C4::Letters::parseletter( $params->{'letter'}, 'biblioitems', $params->{'biblionumber'} ); + if ( my $p = $params->{'biblionumber'} ) { + $table_params{'biblio'} = $p; + $table_params{'biblioitems'} = $p; } - return $params->{'letter'}; + return C4::Letters::GetPreparedLetter ( + module => 'circulation', + letter_code => $params->{'letter_code'}, + branchcode => $table_params{'branches'}, + substitute => $params->{'substitute'}, + tables => \%table_params, + ); } 1; diff --git a/misc/cronjobs/gather_print_notices.pl b/misc/cronjobs/gather_print_notices.pl index a72d6a6..165b16e 100755 --- a/misc/cronjobs/gather_print_notices.pl +++ b/misc/cronjobs/gather_print_notices.pl @@ -39,11 +39,9 @@ use Getopt::Long; sub usage { print STDERR < \$stylesheet, 'h|help' => \$help, ) || usage( 1 ); @@ -71,16 +68,9 @@ exit unless( @messages ); open OUTPUT, '>', File::Spec->catdir( $output_directory, "holdnotices-" . $today->output( 'iso' ) . ".html" ); my $template = C4::Templates::gettemplate( 'batch/print-notices.tmpl', 'intranet', new CGI ); -my $stylesheet_contents = ''; - -if ($stylesheet) { - open STYLESHEET, '<', $stylesheet; - while ( ) { $stylesheet_contents .= $_ } - close STYLESHEET; -} $template->param( - stylesheet => $stylesheet_contents, + stylesheet => C4::Context->preference("NoticeCSS"), today => $today->output(), messages => \@messages, ); diff --git a/misc/cronjobs/overdue_notices.pl b/misc/cronjobs/overdue_notices.pl index 5896abd..d303f4f 100755 --- a/misc/cronjobs/overdue_notices.pl +++ b/misc/cronjobs/overdue_notices.pl @@ -460,16 +460,6 @@ END_SQL { $verbose and warn "borrower $firstname, $lastname ($borrowernumber) has items triggering level $i."; - my $letter = C4::Letters::getletter( 'circulation', $overdue_rules->{"letter$i"} ); - - unless ($letter) { - $verbose and warn "Message '$overdue_rules->{letter$i}' content not found"; - - # might as well skip while PERIOD, no other borrowers are going to work. - # FIXME : Does this mean a letter must be defined in order to trigger a debar ? - next PERIOD; - } - if ( $overdue_rules->{"debarred$i"} ) { #action taken is debarring @@ -494,11 +484,12 @@ END_SQL my @item_info = map { $_ =~ /^date|date$/ ? format_date( $item_info->{$_} ) : $item_info->{$_} || '' } @item_content_fields; $titles .= join("\t", @item_info) . "\n"; $itemcount++; - push @items, { itemnumber => $item_info->{'itemnumber'}, biblionumber => $item_info->{'biblionumber'} }; + push @items, $item_info; } $sth2->finish; - $letter = parse_letter( - { letter => $letter, + + my $letter = parse_letter( + { letter_code => $overdue_rules->{"letter$i"}, borrowernumber => $borrowernumber, branchcode => $branchcode, items => \@items, @@ -509,6 +500,13 @@ END_SQL } } ); + unless ($letter) { + $verbose and warn "Message '$overdue_rules->{letter$i}' content not found"; + + # might as well skip while PERIOD, no other borrowers are going to work. + # FIXME : Does this mean a letter must be defined in order to trigger a debar ? + next PERIOD; + } if ( $exceededPrintNoticesMaxLines ) { $letter->{'content'} .= "List too long for form; please check your account online for a complete list of your overdue items."; @@ -643,54 +641,56 @@ substituted keys and values. =cut -sub parse_letter { # FIXME: this code should probably be moved to C4::Letters:parseletter +sub parse_letter { my $params = shift; - foreach my $required (qw( letter borrowernumber )) { + foreach my $required (qw( letter_code borrowernumber )) { return unless exists $params->{$required}; } - my $todaysdate = C4::Dates->new()->output("syspref"); - $params->{'letter'}->{title} =~ s/<>/$todaysdate/g; - $params->{'letter'}->{content} =~ s/<>/$todaysdate/g; + my $substitute = $params->{'substitute'} || {}; + $substitute->{today} ||= C4::Dates->new()->output("syspref"); - if ( $params->{'substitute'} ) { - while ( my ( $key, $replacedby ) = each %{ $params->{'substitute'} } ) { - my $replacefield = "<<$key>>"; - $params->{'letter'}->{title} =~ s/$replacefield/$replacedby/g; - $params->{'letter'}->{content} =~ s/$replacefield/$replacedby/g; - } + my %tables = ( 'borrowers' => $params->{'borrowernumber'} ); + if ( my $p = $params->{'branchcode'} ) { + $tables{'branches'} = $p; } - $params->{'letter'} = C4::Letters::parseletter( $params->{'letter'}, 'borrowers', $params->{'borrowernumber'} ); - - if ( $params->{'branchcode'} ) { - $params->{'letter'} = C4::Letters::parseletter( $params->{'letter'}, 'branches', $params->{'branchcode'} ); + my $currency_format; + if ($params->{'letter'}->{'content'} =~ m/(.*)<\/fine>/o) { # process any fine tags... + $currency_format = $1; + $params->{'letter'}->{'content'} =~ s/.*<\/fine>/<>/o; } - if ( $params->{'items'} ) { + my @item_tables; + if ( my $i = $params->{'items'} ) { my $item_format = ''; - PROCESS_ITEMS: - while (scalar(@{$params->{'items'}}) > 0) { - my $item = shift @{$params->{'items'}}; + foreach my $item (@$i) { my $fine = GetFine($item->{'itemnumber'}, $params->{'borrowernumber'}); if (!$item_format) { $params->{'letter'}->{'content'} =~ m/(.*<\/item>)/; $item_format = $1; } - if ($params->{'letter'}->{'content'} =~ m/(.*)<\/fine>/) { # process any fine tags... - my $formatted_fine = currency_format("$1", "$fine", FMT_SYMBOL); - $params->{'letter'}->{'content'} =~ s/.*<\/fine>/$formatted_fine/; - } - $params->{'letter'} = C4::Letters::parseletter( $params->{'letter'}, 'biblio', $item->{'biblionumber'} ); - $params->{'letter'} = C4::Letters::parseletter( $params->{'letter'}, 'biblioitems', $item->{'biblionumber'} ); - $params->{'letter'} = C4::Letters::parseletter( $params->{'letter'}, 'items', $item->{'itemnumber'} ); - $params->{'letter'} = C4::Letters::parseletter( $params->{'letter'}, 'issues', $item->{'itemnumber'} ); - $params->{'letter'}->{'content'} =~ s/(.*<\/item>)/$1\n$item_format/ if scalar(@{$params->{'items'}} > 0); + $item->{'fine'} = currency_format($currency_format, "$fine", FMT_SYMBOL) + if $currency_format; + + push @item_tables, { + 'biblio' => $item->{'biblionumber'}, + 'biblioitems' => $item->{'biblionumber'}, + 'items' => $item, + 'issues' => $item->{'itemnumber'}, + }; } } - $params->{'letter'}->{'content'} =~ s/<\/{0,1}?item>//g; # strip all remaining item tags... - return $params->{'letter'}; + + return C4::Letters::GetPreparedLetter ( + module => 'circulation', + letter_code => $params->{'letter_code'}, + branchcode => $params->{'branchcode'}, + tables => \%tables, + substitute => $substitute, + repeat => { item => \@item_tables }, + ); } =head2 prepare_letter_for_printing diff --git a/t/db_dependent/lib/KohaTest/Letters.pm b/t/db_dependent/lib/KohaTest/Letters.pm index 97d58fb..f2d7b0d 100644 --- a/t/db_dependent/lib/KohaTest/Letters.pm +++ b/t/db_dependent/lib/KohaTest/Letters.pm @@ -12,13 +12,12 @@ sub testing_class { 'C4::Letters' }; sub methods : Test( 1 ) { my $self = shift; - my @methods = qw( getletter - addalert + my @methods = qw( addalert delalert getalert findrelatedto SendAlerts - parseletter + GetPreparedLetter ); can_ok( $self->testing_class, @methods ); diff --git a/t/db_dependent/lib/KohaTest/Letters/GetLetter.pm b/t/db_dependent/lib/KohaTest/Letters/GetLetter.pm index 76b6ab4..53e5439 100644 --- a/t/db_dependent/lib/KohaTest/Letters/GetLetter.pm +++ b/t/db_dependent/lib/KohaTest/Letters/GetLetter.pm @@ -10,7 +10,7 @@ use Test::More; sub GetLetter : Test( 6 ) { my $self = shift; - my $letter = getletter( 'circulation', 'ODUE' ); + my $letter = getletter( 'circulation', 'ODUE', '' ); isa_ok( $letter, 'HASH' ) or diag( Data::Dumper->Dump( [ $letter ], [ 'letter' ] ) ); @@ -21,7 +21,6 @@ sub GetLetter : Test( 6 ) { ok( exists $letter->{'name'}, 'name' ); ok( exists $letter->{'title'}, 'title' ); - } 1; diff --git a/t/db_dependent/lib/KohaTest/Members.pm b/t/db_dependent/lib/KohaTest/Members.pm index 5646be1..dfde7da 100644 --- a/t/db_dependent/lib/KohaTest/Members.pm +++ b/t/db_dependent/lib/KohaTest/Members.pm @@ -52,6 +52,7 @@ sub methods : Test( 1 ) { GetBorrowersWhoHaveNeverBorrowed GetBorrowersWithIssuesHistoryOlderThan GetBorrowersNamesAndLatestIssue + IssueSlip ); can_ok( $self->testing_class, @methods ); diff --git a/t/db_dependent/lib/KohaTest/Print.pm b/t/db_dependent/lib/KohaTest/Print.pm index 02fd5fb..d35ab34 100644 --- a/t/db_dependent/lib/KohaTest/Print.pm +++ b/t/db_dependent/lib/KohaTest/Print.pm @@ -12,10 +12,7 @@ sub testing_class { 'C4::Print' }; sub methods : Test( 1 ) { my $self = shift; - my @methods = qw( remoteprint - printreserve - printslip - ); + my @methods = qw( printslip ); can_ok( $self->testing_class, @methods ); } diff --git a/t/db_dependent/lib/KohaTest/Reserves.pm b/t/db_dependent/lib/KohaTest/Reserves.pm index 8b05dd0..6416ac3 100644 --- a/t/db_dependent/lib/KohaTest/Reserves.pm +++ b/t/db_dependent/lib/KohaTest/Reserves.pm @@ -33,6 +33,7 @@ sub methods : Test( 1 ) { GetReserveInfo _FixPriority _Findgroupreserve + ReserveSlip ); can_ok( $self->testing_class, @methods ); diff --git a/tools/letter.pl b/tools/letter.pl index 04cd7d2..ae47810 100755 --- a/tools/letter.pl +++ b/tools/letter.pl @@ -46,14 +46,35 @@ use CGI; use C4::Auth; use C4::Context; use C4::Output; +use C4::Branch; # GetBranches +use C4::Members::Attributes; -# letter_exists($module, $code) -# - return true if a letter with the given $module and $code exists +# _letter_from_where($branchcode,$module, $code) +# - return FROM WHERE clause and bind args for a letter +sub _letter_from_where { + my ($branchcode, $module, $code) = @_; + my $sql = q{FROM letter WHERE branchcode = ? AND module = ? AND code = ?}; + my @args = ($branchcode || '', $module, $code); +# Mysql is retarded. cause branchcode is part of the primary key it cannot be null. How does that +# work with foreign key constraint I wonder... + +# if ($branchcode) { +# $sql .= " AND branchcode = ?"; +# push @args, $branchcode; +# } else { +# $sql .= " AND branchcode IS NULL"; +# } + + return ($sql, \@args); +} + +# letter_exists($branchcode,$module, $code) +# - return true if a letter with the given $branchcode, $module and $code exists sub letter_exists { - my ($module, $code) = @_; + my ($sql, $args) = _letter_from_where(@_); my $dbh = C4::Context->dbh; - my $letters = $dbh->selectall_arrayref(q{SELECT name FROM letter WHERE module = ? AND code = ?}, undef, $module, $code); - return @{$letters}; + my $letter = $dbh->selectrow_hashref("SELECT * $sql", undef, @$args); + return $letter; } # $protected_letters = protected_letters() @@ -67,16 +88,14 @@ sub protected_letters { my $input = new CGI; my $searchfield = $input->param('searchfield'); my $script_name = '/cgi-bin/koha/tools/letter.pl'; +my $branchcode = $input->param('branchcode'); my $code = $input->param('code'); my $module = $input->param('module'); my $content = $input->param('content'); -my $op = $input->param('op'); +my $op = $input->param('op') || ''; my $dbh = C4::Context->dbh; -if (!defined $module ) { - $module = q{}; -} -my ( $template, $borrowernumber, $cookie ) = get_template_and_user( +my ( $template, $borrowernumber, $cookie, $staffflags ) = get_template_and_user( { template_name => 'tools/letter.tmpl', query => $input, @@ -87,32 +106,39 @@ my ( $template, $borrowernumber, $cookie ) = get_template_and_user( } ); -if (!defined $op) { - $op = q{}; # silence errors from eq -} +my $my_branch = C4::Context->preference("IndependantBranches") && !$staffflags->{'superlibrarian'} + ? C4::Context->userenv()->{'branch'} + : undef; # we show only the TMPL_VAR names $op $template->param( + independant_branch => $my_branch, script_name => $script_name, + searchfield => $searchfield, action => $script_name ); +if ($op eq 'copy') { + add_copy(); + $op = 'add_form'; +} + if ($op eq 'add_form') { - add_form($module, $code); + add_form($branchcode, $module, $code); } elsif ( $op eq 'add_validate' ) { add_validate(); $op = q{}; # next operation is to return to default screen } elsif ( $op eq 'delete_confirm' ) { - delete_confirm($module, $code); + delete_confirm($branchcode, $module, $code); } elsif ( $op eq 'delete_confirmed' ) { - delete_confirmed($module, $code); + delete_confirmed($branchcode, $module, $code); $op = q{}; # next operation is to return to default screen } else { - default_display($searchfield); + default_display($branchcode,$searchfield); } # Do this last as delete_confirmed resets @@ -125,23 +151,21 @@ if ($op) { output_html_with_http_headers $input, $cookie, $template->output; sub add_form { - my ($module, $code ) = @_; + my ($branchcode,$module, $code ) = @_; my $letter; # if code has been passed we can identify letter and its an update action if ($code) { - $letter = $dbh->selectrow_hashref(q{SELECT module, code, name, title, content FROM letter WHERE module=? AND code=?}, - undef, $module, $code); + $letter = letter_exists($branchcode,$module, $code); + } + if ($letter) { $template->param( modify => 1 ); $template->param( code => $letter->{code} ); } else { # initialize the new fields $letter = { - module => $module, - code => q{}, - name => q{}, - title => q{}, - content => q{}, + branchcode => $branchcode, + module => $module, }; $template->param( adding => 1 ); } @@ -173,14 +197,20 @@ sub add_form { {value => q{}, text => '---ITEMS---' }, {value => 'items.content', text => 'items.content'}, add_fields('issues','borrowers'); + if ($module eq 'circulation') { + push @{$field_selection}, add_fields('opac_news'); + } } $template->param( - name => $letter->{name}, - title => $letter->{title}, - content => $letter->{content}, - module => $module, - $module => 1, + branchcode => $letter->{branchcode}, + name => $letter->{name}, + is_html => $letter->{is_html}, + title => $letter->{title}, + content => $letter->{content}, + module => $module, + $module => 1, + branchloop => _branchloop($branchcode), SQLfieldname => $field_selection, ); return; @@ -188,37 +218,56 @@ sub add_form { sub add_validate { my $dbh = C4::Context->dbh; - my $module = $input->param('module'); - my $oldmodule = $input->param('oldmodule'); - my $code = $input->param('code'); - my $name = $input->param('name'); - my $title = $input->param('title'); - my $content = $input->param('content'); - if (letter_exists($oldmodule, $code)) { + my $oldbranchcode = $input->param('oldbranchcode'); + my $branchcode = $input->param('branchcode') || ''; + my $module = $input->param('module'); + my $oldmodule = $input->param('oldmodule'); + my $code = $input->param('code'); + my $name = $input->param('name'); + my $is_html = $input->param('is_html'); + my $title = $input->param('title'); + my $content = $input->param('content'); + if (letter_exists($oldbranchcode,$oldmodule, $code)) { $dbh->do( - q{UPDATE letter SET module = ?, code = ?, name = ?, title = ?, content = ? WHERE module = ? AND code = ?}, + q{UPDATE letter SET branchcode = ?, module = ?, name = ?, is_html = ?, title = ?, content = ? WHERE branchcode = ? AND module = ? AND code = ?}, undef, - $module, $code, $name, $title, $content, - $oldmodule, $code + $branchcode, $module, $name, $is_html || 0, $title, $content, + $oldbranchcode, $oldmodule, $code ); } else { $dbh->do( - q{INSERT INTO letter (module,code,name,title,content) VALUES (?,?,?,?,?)}, + q{INSERT INTO letter (branchcode,module,code,name,is_html,title,content) VALUES (?,?,?,?,?,?,?)}, undef, - $module, $code, $name, $title, $content + $branchcode, $module, $code, $name, $is_html || 0, $title, $content ); } # set up default display - default_display(); - return; + default_display($branchcode); +} + +sub add_copy { + my $dbh = C4::Context->dbh; + my $oldbranchcode = $input->param('oldbranchcode'); + my $branchcode = $input->param('branchcode'); + my $module = $input->param('module'); + my $code = $input->param('code'); + + return if letter_exists($branchcode,$module, $code); + + my $old_letter = letter_exists($oldbranchcode,$module, $code); + + $dbh->do( + q{INSERT INTO letter (branchcode,module,code,name,is_html,title,content) VALUES (?,?,?,?,?,?,?)}, + undef, + $branchcode, $module, $code, $old_letter->{name}, $old_letter->{is_html}, $old_letter->{title}, $old_letter->{content} + ); } sub delete_confirm { - my ($module, $code) = @_; + my ($branchcode, $module, $code) = @_; my $dbh = C4::Context->dbh; - my $letter = $dbh->selectrow_hashref(q|SELECT name FROM letter WHERE module = ? AND code = ?|, - { Slice => {} }, - $module, $code); + my $letter = letter_exists($branchcode, $module, $code); + $template->param( branchcode => $branchcode, branchname => GetBranchName($branchcode) ); $template->param( code => $code ); $template->param( module => $module); $template->param( name => $letter->{name}); @@ -226,40 +275,53 @@ sub delete_confirm { } sub delete_confirmed { - my ($module, $code) = @_; + my ($branchcode, $module, $code) = @_; + my ($sql, $args) = _letter_from_where($branchcode, $module, $code); my $dbh = C4::Context->dbh; - $dbh->do('DELETE FROM letter WHERE module=? AND code=?',{},$module,$code); + $dbh->do("DELETE $sql", undef, @$args); # setup default display for screen - default_display(); + default_display($branchcode); return; } sub retrieve_letters { - my $searchstring = shift; + my ($branchcode, $searchstring) = @_; + + $branchcode = $my_branch if $branchcode && $my_branch; + my $dbh = C4::Context->dbh; - if ($searchstring) { - if ($searchstring=~m/(\S+)/) { - $searchstring = $1 . q{%}; - return $dbh->selectall_arrayref('SELECT module, code, name FROM letter WHERE code LIKE ? ORDER BY module, code', - { Slice => {} }, $searchstring); - } + my ($sql, @where, @args); + $sql = "SELECT branchcode, module, code, name, branchname + FROM letter + LEFT OUTER JOIN branches USING (branchcode)"; + if ($searchstring && $searchstring=~m/(\S+)/) { + $searchstring = $1 . q{%}; + push @where, 'code LIKE ?'; + push @args, $searchstring; } - else { - return $dbh->selectall_arrayref('SELECT module, code, name FROM letter ORDER BY module, code', { Slice => {} }); + elsif ($branchcode) { + push @where, 'branchcode = ?'; + push @args, $branchcode || ''; } - return; + elsif ($my_branch) { + push @where, "(branchcode = ? OR branchcode = '')"; + push @args, $my_branch; + } + + $sql .= " WHERE ".join(" AND ", @where) if @where; + $sql .= " ORDER BY module, code, branchcode"; +# use Data::Dumper; die Dumper($sql, \@args); + return $dbh->selectall_arrayref($sql, { Slice => {} }, @args); } sub default_display { - my $searchfield = shift; - my $results; + my ($branchcode, $searchfield) = @_; + if ( $searchfield ) { $template->param( search => 1 ); - $template->param( searchfield => $searchfield ); - $results = retrieve_letters($searchfield); - } else { - $results = retrieve_letters(); } + my $results = retrieve_letters($branchcode,$searchfield); + my $loop_data = []; my $protected_letters = protected_letters(); foreach my $row (@{$results}) { @@ -267,8 +329,27 @@ sub default_display { push @{$loop_data}, $row; } - $template->param( letter => $loop_data ); - return; + + $template->param( + letter => $loop_data, + branchloop => _branchloop($branchcode), + ); +} + +sub _branchloop { + my ($branchcode) = @_; + + my $branches = GetBranches(); + my @branchloop; + for my $thisbranch (sort { $branches->{$a}->{branchname} cmp $branches->{$b}->{branchname} } keys %$branches) { + push @branchloop, { + value => $thisbranch, + selected => $branchcode && $thisbranch eq $branchcode, + branchname => $branches->{$thisbranch}->{'branchname'}, + }; + } + + return \@branchloop; } sub add_fields { @@ -307,6 +388,7 @@ sub get_columns_for { text => $tlabel, }; } + my $sql = "SHOW COLUMNS FROM $table";# TODO not db agnostic my $table_prefix = $table . q|.|; my $rows = C4::Context->dbh->selectall_arrayref($sql, { Slice => {} }); @@ -317,5 +399,15 @@ sub get_columns_for { text => $table_prefix . $row->{Field}, } } + if ($table eq 'borrowers') { + if ( my $attributes = C4::Members::Attributes::GetAttributes() ) { + foreach (@$attributes) { + push @fields, { + value => "borrower-attribute:$_", + text => "attribute:$_", + } + } + } + } return @fields; } -- 1.6.5 From srdjan at catalyst.net.nz Wed Feb 22 07:29:58 2012 From: srdjan at catalyst.net.nz (Srdjan) Date: Wed, 22 Feb 2012 16:29:58 +1000 Subject: [Koha-patches] Patch 5668 Message-ID: <4F448B66.20508@catalyst.net.nz> -------------- next part -------------- A non-text attachment was scrubbed... Name: 0001-Bug-5668-star-ratings-in-the-OPAC.patch Type: text/x-patch Size: 38179 bytes Desc: not available URL: From srdjan at catalyst.net.nz Wed Feb 22 09:36:49 2012 From: srdjan at catalyst.net.nz (Srdjan Jankovic) Date: Wed, 22 Feb 2012 21:36:49 +1300 Subject: [Koha-patches] [PATCH] bug_5911: Transport Cost Matrix In-Reply-To: References: Message-ID: <1329899809-20502-1-git-send-email-srdjan@catalyst.net.nz> Create transport_cost table, added UseTransportCostMatrix syspref. transport_cost table contains normalised branch to branch transfer costs. These are used for fulilling inter-branch hold transfers. Moved GetHoldsQueueItems() from .pl to HoldsQueue.pm --- C4/Context.pm | 3 + C4/HoldsQueue.pm | 630 ++++++++++++++++++++ admin/systempreferences.pl | 1 + admin/transport-cost-matrix.pl | 122 ++++ circ/view_holdsqueue.pl | 34 +- installer/data/mysql/kohastructure.sql | 15 + installer/data/mysql/sysprefs.sql | 2 + installer/data/mysql/updatedatabase.pl | 20 + .../prog/en/modules/admin/admin-home.tt | 2 + .../prog/en/modules/admin/transport-cost-matrix.tt | 126 ++++ misc/cronjobs/holds/build_holds_queue.pl | 382 +------------ t/db_dependent/HoldsQueue.t | 161 +++++ 12 files changed, 1086 insertions(+), 412 deletions(-) create mode 100755 C4/HoldsQueue.pm create mode 100755 admin/transport-cost-matrix.pl create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/admin/transport-cost-matrix.tt create mode 100755 t/db_dependent/HoldsQueue.t diff --git a/C4/Context.pm b/C4/Context.pm index 0417c45..07a1040 100644 --- a/C4/Context.pm +++ b/C4/Context.pm @@ -521,6 +521,9 @@ with this method. # flushing the caching mechanism. my %sysprefs; +sub _flush_preferences { + %sysprefs = (); +} sub preference { my $self = shift; diff --git a/C4/HoldsQueue.pm b/C4/HoldsQueue.pm new file mode 100755 index 0000000..5ed122f --- /dev/null +++ b/C4/HoldsQueue.pm @@ -0,0 +1,630 @@ +package C4::HoldsQueue; + +# Copyright 2011 Catalyst IT +# +# 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +# FIXME: expand perldoc, explain intended logic + +use strict; +use warnings; + +use C4::Context; +use C4::Search; +use C4::Items; +use C4::Branch; +use C4::Circulation; +use C4::Members; +use C4::Biblio; +use C4::Dates qw/format_date/; + +use List::Util qw(shuffle); +use Data::Dumper; + +use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); +BEGIN { + $VERSION = 3.03; + require Exporter; + @ISA = qw(Exporter); + @EXPORT_OK = qw( + &CreateQueue + &GetHoldsQueueItems + + &SetUseTransportCostMatrix + &TransportCostMatrix + &UpdateTransportCostMatrix + ); +} + +# XXX This is not safe in a persistant environment +my $dbh = C4::Context->dbh; + +=head1 FUNCTIONS + +=head2 SetUseTransportCostMatrix + + SetUseTransportCostMatrix($true_false); + +Updates UseTransportCostMatrix syspref + +=cut + +sub SetUseTransportCostMatrix { + my ($bool) = @_; + + $dbh->do("UPDATE systempreferences SET value=? WHERE variable='UseTransportCostMatrix'", undef, $bool ? '1' : '0'); +} + +=head2 TransportCostMatrix + + TransportCostMatrix(); + +Returns Transport Cost Matrix as a hashref => => cost + +=cut + +sub TransportCostMatrix { + my $transport_costs = $dbh->selectall_arrayref("SELECT * FROM transport_cost",{ Slice => {} }); + + my %transport_cost_matrix; + foreach (@$transport_costs) { + my $from = $_->{frombranch}; + my $to = $_->{tobranch}; + my $cost = $_->{cost}; + my $disabled = $_->{disable_transfer}; + $transport_cost_matrix{$to}{$from} = { cost => $cost, disable_transfer => $disabled }; + } + return \%transport_cost_matrix; +} + +=head2 UpdateTransportCostMatrix + + UpdateTransportCostMatrix($records); + +Updates full Transport Cost Matrix table. $records is an arrayref of records. +Records: { frombranch => , tobranch => , cost =>
    , disable_transfer => <0,1> } + +=cut + +sub UpdateTransportCostMatrix { + my ($records) = @_; + + my $sth = $dbh->prepare("INSERT INTO transport_cost (frombranch, tobranch, cost, disable_transfer) VALUES (?, ?, ?, ?)"); + + $dbh->do("TRUNCATE TABLE transport_cost"); + foreach (@$records) { + my $cost = $_->{cost}; + my $from = $_->{frombranch}; + my $to = $_->{tobranch}; + if ( !defined ($cost) || ($cost !~ m/0(\.[0.9]*)?|1(.0*)?/o) ) { + warn "Invalid $from -> $to cost $cost - nust be a decimal number in 0 to 1 range, forcing to 1"; + $cost = 1; + } + $sth->execute( $from, $to, $cost, $_->{disable_transfer} ? 1 : 0 ); + } +} + +=head2 GetHoldsQueueItems + + GetHoldsQueueItems($branch); + +Returns hold queue for a holding branch. If branch is omitted, then whole queue is returned + +=cut + +sub GetHoldsQueueItems { + my ($branchlimit) = @_; + + my @bind_params = (); + my $query = q/SELECT tmp_holdsqueue.*, biblio.author, items.ccode, items.location, items.enumchron, items.cn_sort, biblioitems.publishercode,biblio.copyrightdate,biblioitems.publicationyear,biblioitems.pages,biblioitems.size,biblioitems.publicationyear,biblioitems.isbn,items.copynumber + FROM tmp_holdsqueue + JOIN biblio USING (biblionumber) + LEFT JOIN biblioitems USING (biblionumber) + LEFT JOIN items USING ( itemnumber) + /; + if ($branchlimit) { + $query .=" WHERE tmp_holdsqueue.holdingbranch = ?"; + push @bind_params, $branchlimit; + } + $query .= " ORDER BY ccode, location, cn_sort, author, title, pickbranch, reservedate"; + my $sth = $dbh->prepare($query); + $sth->execute(@bind_params); + my $items = []; + while ( my $row = $sth->fetchrow_hashref ){ + $row->{reservedate} = format_date($row->{reservedate}); + my $record = GetMarcBiblio($row->{biblionumber}); + if ($record){ + $row->{subtitle} = GetRecordValue('subtitle',$record,'')->[0]->{subfield}; + $row->{parts} = GetRecordValue('parts',$record,'')->[0]->{subfield}; + $row->{numbers} = GetRecordValue('numbers',$record,'')->[0]->{subfield}; + } + push @$items, $row; + } + return $items; +} + +=head2 CreateQueue + + CreateQueue(); + +Top level function that turns reserves into tmp_holdsqueue and hold_fill_targets. + +=cut + +sub CreateQueue { + + $dbh->do("DELETE FROM tmp_holdsqueue"); # clear the old table for new info + $dbh->do("DELETE FROM hold_fill_targets"); + + my $total_bibs = 0; + my $total_requests = 0; + my $total_available_items = 0; + my $num_items_mapped = 0; + + my $branches_to_use; + my $transport_cost_matrix; + my $use_transport_cost_matrix = C4::Context->preference("UseTransportCostMatrix"); + if ($use_transport_cost_matrix) { + debug( "Using cost matrix" ); + $transport_cost_matrix = TransportCostMatrix(); + unless (keys %$transport_cost_matrix) { + warn "UseTransportCostMatrix set to yes, but matrix not populated"; + undef $transport_cost_matrix; + } + } + unless ($transport_cost_matrix) { + debug( "Not using cost matrix" ); + $branches_to_use = load_branches_to_pull_from(); + } + + my $bibs_with_pending_requests = GetBibsWithPendingHoldRequests(); + debug( "bibs_with_pending_requests: ".Dumper($bibs_with_pending_requests) ); + + foreach my $biblionumber (@$bibs_with_pending_requests) { + $total_bibs++; + my $hold_requests = GetPendingHoldRequestsForBib($biblionumber); + my $available_items = GetItemsAvailableToFillHoldRequestsForBib($biblionumber, $branches_to_use); + $total_requests += scalar(@$hold_requests); + $total_available_items += scalar(@$available_items); + + my $item_map = MapItemsToHoldRequests($hold_requests, $available_items, $branches_to_use, $transport_cost_matrix); + $item_map or next; + my $item_map_size = scalar(keys %$item_map) + or next;; + + $num_items_mapped += $item_map_size; + CreatePicklistFromItemMap($item_map); + AddToHoldTargetMap($item_map); + if (($item_map_size < scalar(@$hold_requests )) and + ($item_map_size < scalar(@$available_items))) { + # DOUBLE CHECK, but this is probably OK - unfilled item-level requests + # FIXME + #warn "unfilled requests for $biblionumber"; + #warn Dumper($hold_requests), Dumper($available_items), Dumper($item_map); + } + } +} + +=head2 GetBibsWithPendingHoldRequests + + my $biblionumber_aref = GetBibsWithPendingHoldRequests(); + +Return an arrayref of the biblionumbers of all bibs +that have one or more unfilled hold requests. + +=cut + +sub GetBibsWithPendingHoldRequests { + my $dbh = C4::Context->dbh; + + my $bib_query = "SELECT DISTINCT biblionumber + FROM reserves + WHERE found IS NULL + AND priority > 0 + AND reservedate <= CURRENT_DATE()"; + my $sth = $dbh->prepare($bib_query); + + $sth->execute(); + my $biblionumbers = $sth->fetchall_arrayref(); + + return [ map { $_->[0] } @$biblionumbers ]; +} + +=head2 GetPendingHoldRequestsForBib + + my $requests = GetPendingHoldRequestsForBib($biblionumber); + +Returns an arrayref of hashrefs to pending, unfilled hold requests +on the bib identified by $biblionumber. The following keys +are present in each hashref: + + biblionumber + borrowernumber + itemnumber + priority + branchcode + reservedate + reservenotes + borrowerbranch + +The arrayref is sorted in order of increasing priority. + +=cut + +sub GetPendingHoldRequestsForBib { + my $biblionumber = shift; + + my $dbh = C4::Context->dbh; + + my $request_query = "SELECT biblionumber, borrowernumber, itemnumber, priority, reserves.branchcode, + reservedate, reservenotes, borrowers.branchcode AS borrowerbranch + FROM reserves + JOIN borrowers USING (borrowernumber) + WHERE biblionumber = ? + AND found IS NULL + AND priority > 0 + AND reservedate <= CURRENT_DATE() + ORDER BY priority"; + my $sth = $dbh->prepare($request_query); + $sth->execute($biblionumber); + + my $requests = $sth->fetchall_arrayref({}); + return $requests; + +} + +=head2 GetItemsAvailableToFillHoldRequestsForBib + + my $available_items = GetItemsAvailableToFillHoldRequestsForBib($biblionumber, $branches_ar); + +Returns an arrayref of items available to fill hold requests +for the bib identified by C<$biblionumber>. An item is available +to fill a hold request if and only if: + + * it is not on loan + * it is not withdrawn + * it is not marked notforloan + * it is not currently in transit + * it is not lost + * it is not sitting on the hold shelf + +=cut + +sub GetItemsAvailableToFillHoldRequestsForBib { + my ($biblionumber, $branches_to_use) = @_; + + my $dbh = C4::Context->dbh; + my $items_query = "SELECT itemnumber, homebranch, holdingbranch, itemtypes.itemtype AS itype + FROM items "; + + if (C4::Context->preference('item-level_itypes')) { + $items_query .= "LEFT JOIN itemtypes ON (itemtypes.itemtype = items.itype) "; + } else { + $items_query .= "JOIN biblioitems USING (biblioitemnumber) + LEFT JOIN itemtypes USING (itemtype) "; + } + $items_query .= "WHERE items.notforloan = 0 + AND holdingbranch IS NOT NULL + AND itemlost = 0 + AND wthdrawn = 0 + AND items.onloan IS NULL + AND (itemtypes.notforloan IS NULL OR itemtypes.notforloan = 0) + AND itemnumber NOT IN ( + SELECT itemnumber + FROM reserves + WHERE biblionumber = ? + AND itemnumber IS NOT NULL + AND (found IS NOT NULL OR priority = 0) + ) + AND items.biblionumber = ?"; + $items_query .= " AND damaged = 0 " + unless C4::Context->preference('AllowHoldsOnDamagedItems'); + + my @params = ($biblionumber, $biblionumber); + if ($branches_to_use && @$branches_to_use) { + $items_query .= " AND holdingbranch IN (" . join (",", map { "?" } @$branches_to_use) . ")"; + push @params, @$branches_to_use; + } + my $sth = $dbh->prepare($items_query); + $sth->execute(@params); + + my $items = $sth->fetchall_arrayref({}); + $items = [ grep { my @transfers = GetTransfers($_->{itemnumber}); $#transfers == -1; } @$items ]; + map { my $rule = GetBranchItemRule($_->{homebranch}, $_->{itype}); $_->{holdallowed} = $rule->{holdallowed}; $rule->{holdallowed} != 0 } @$items; + return [ grep { $_->{holdallowed} != 0 } @$items ]; +} + +=head2 MapItemsToHoldRequests + + MapItemsToHoldRequests($hold_requests, $available_items, $branches, $transport_cost_matrix) + +=cut + +sub MapItemsToHoldRequests { + my ($hold_requests, $available_items, $branches_to_use, $transport_cost_matrix) = @_; + + # handle trival cases + return unless scalar(@$hold_requests) > 0; + return unless scalar(@$available_items) > 0; + + debug( "MapItemsToHoldRequests() for ".Dumper($hold_requests, $available_items, $branches_to_use, $transport_cost_matrix) ); + my $automatic_return = C4::Context->preference("AutomaticItemReturn"); + + # identify item-level requests + my %specific_items_requested = map { $_->{itemnumber} => 1 } + grep { defined($_->{itemnumber}) } + @$hold_requests; + + # group available items by itemnumber + my %items_by_itemnumber = map { $_->{itemnumber} => $_ } @$available_items; + + # items already allocated + my %allocated_items = (); + + # map of items to hold requests + my %item_map = (); + + # figure out which item-level requests can be filled + my $num_items_remaining = scalar(@$available_items); + foreach my $request (@$hold_requests) { + last if $num_items_remaining == 0; + + # is this an item-level request? + if (defined($request->{itemnumber})) { + # fill it if possible; if not skip it + if (exists $items_by_itemnumber{$request->{itemnumber}} and + not exists $allocated_items{$request->{itemnumber}}) { + $item_map{$request->{itemnumber}} = { + borrowernumber => $request->{borrowernumber}, + biblionumber => $request->{biblionumber}, + holdingbranch => $items_by_itemnumber{$request->{itemnumber}}->{holdingbranch}, + pickup_branch => $request->{branchcode} || $request->{borrowerbranch}, + item_level => 1, + reservedate => $request->{reservedate}, + reservenotes => $request->{reservenotes}, + }; + $allocated_items{$request->{itemnumber}}++; + $num_items_remaining--; + } + } else { + # it's title-level request that will take up one item + $num_items_remaining--; + } + } + + # group available items by branch + my %items_by_branch = (); + foreach my $item (@$available_items) { + next unless $item->{holdallowed}; + + push @{ $items_by_branch{ $automatic_return ? $item->{homebranch} + : $item->{holdingbranch} } }, $item + unless exists $allocated_items{ $item->{itemnumber} }; + } + return unless keys %items_by_branch; + + # now handle the title-level requests + $num_items_remaining = scalar(@$available_items) - scalar(keys %allocated_items); + my $pull_branches; + foreach my $request (@$hold_requests) { + last if $num_items_remaining == 0; + next if defined($request->{itemnumber}); # already handled these + + # look for local match first + my $pickup_branch = $request->{branchcode} || $request->{borrowerbranch}; + my ($itemnumber, $holdingbranch); + + my $holding_branch_items = $automatic_return ? undef : $items_by_branch{$pickup_branch}; + if ( $holding_branch_items ) { + foreach my $item (@$holding_branch_items) { + if ( $request->{borrowerbranch} eq $item->{homebranch} ) { + $itemnumber = $item->{itemnumber}; + last; + } + } + $holdingbranch = $pickup_branch; + $itemnumber ||= $holding_branch_items->[0]->{itemnumber}; + } + elsif ($transport_cost_matrix) { + $pull_branches = [keys %items_by_branch]; + $holdingbranch = least_cost_branch( $pickup_branch, $pull_branches, $transport_cost_matrix ); + if ( $holdingbranch ) { + + my $holding_branch_items = $items_by_branch{$holdingbranch}; + foreach my $item (@$holding_branch_items) { + next if $request->{borrowerbranch} ne $item->{homebranch}; + + $itemnumber = $item->{itemnumber}; + last; + } + $itemnumber ||= $holding_branch_items->[0]->{itemnumber}; + } + else { + warn "No transport costs for $pickup_branch"; + } + } + + unless ($itemnumber) { + # not found yet, fall back to basics + if ($branches_to_use) { + $pull_branches = $branches_to_use; + } else { + $pull_branches = [keys %items_by_branch]; + } + PULL_BRANCHES: + foreach my $branch (@$pull_branches) { + my $holding_branch_items = $items_by_branch{$branch} + or next; + + $holdingbranch ||= $branch; + foreach my $item (@$holding_branch_items) { + next if $pickup_branch ne $item->{homebranch}; + + $itemnumber = $item->{itemnumber}; + $holdingbranch = $branch; + last PULL_BRANCHES; + } + } + $itemnumber ||= $items_by_branch{$holdingbranch}->[0]->{itemnumber} + if $holdingbranch; + } + + if ($itemnumber) { + my $holding_branch_items = $items_by_branch{$holdingbranch} + or die "Have $itemnumber, $holdingbranch, but no items!"; + @$holding_branch_items = grep { $_->{itemnumber} != $itemnumber } @$holding_branch_items; + delete $items_by_branch{$holdingbranch} unless @$holding_branch_items; + + $item_map{$itemnumber} = { + borrowernumber => $request->{borrowernumber}, + biblionumber => $request->{biblionumber}, + holdingbranch => $holdingbranch, + pickup_branch => $pickup_branch, + item_level => 0, + reservedate => $request->{reservedate}, + reservenotes => $request->{reservenotes}, + }; + $num_items_remaining--; + } + } + return \%item_map; +} + +=head2 CreatePickListFromItemMap + +=cut + +sub CreatePicklistFromItemMap { + my $item_map = shift; + + my $dbh = C4::Context->dbh; + + my $sth_load=$dbh->prepare(" + INSERT INTO tmp_holdsqueue (biblionumber,itemnumber,barcode,surname,firstname,phone,borrowernumber, + cardnumber,reservedate,title, itemcallnumber, + holdingbranch,pickbranch,notes, item_level_request) + VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) + "); + + foreach my $itemnumber (sort keys %$item_map) { + my $mapped_item = $item_map->{$itemnumber}; + my $biblionumber = $mapped_item->{biblionumber}; + my $borrowernumber = $mapped_item->{borrowernumber}; + my $pickbranch = $mapped_item->{pickup_branch}; + my $holdingbranch = $mapped_item->{holdingbranch}; + my $reservedate = $mapped_item->{reservedate}; + my $reservenotes = $mapped_item->{reservenotes}; + my $item_level = $mapped_item->{item_level}; + + my $item = GetItem($itemnumber); + my $barcode = $item->{barcode}; + my $itemcallnumber = $item->{itemcallnumber}; + + my $borrower = GetMember('borrowernumber'=>$borrowernumber); + my $cardnumber = $borrower->{'cardnumber'}; + my $surname = $borrower->{'surname'}; + my $firstname = $borrower->{'firstname'}; + my $phone = $borrower->{'phone'}; + + my $bib = GetBiblioData($biblionumber); + my $title = $bib->{title}; + + $sth_load->execute($biblionumber, $itemnumber, $barcode, $surname, $firstname, $phone, $borrowernumber, + $cardnumber, $reservedate, $title, $itemcallnumber, + $holdingbranch, $pickbranch, $reservenotes, $item_level); + } +} + +=head2 AddToHoldTargetMap + +=cut + +sub AddToHoldTargetMap { + my $item_map = shift; + + my $dbh = C4::Context->dbh; + + my $insert_sql = q( + INSERT INTO hold_fill_targets (borrowernumber, biblionumber, itemnumber, source_branchcode, item_level_request) + VALUES (?, ?, ?, ?, ?) + ); + my $sth_insert = $dbh->prepare($insert_sql); + + foreach my $itemnumber (keys %$item_map) { + my $mapped_item = $item_map->{$itemnumber}; + $sth_insert->execute($mapped_item->{borrowernumber}, $mapped_item->{biblionumber}, $itemnumber, + $mapped_item->{holdingbranch}, $mapped_item->{item_level}); + } +} + +# Helper functions, not part of any interface + +sub debug { +# warn @_; +} + +sub load_branches_to_pull_from { + my $static_branch_list = C4::Context->preference("StaticHoldsQueueWeight") + or return; + + my @branches_to_use = map { s/^\s+//; s/\s+$//; $_; } split /,/, $static_branch_list; + + @branches_to_use = shuffle(@branches_to_use) if C4::Context->preference("RandomizeHoldsQueueWeight"); + + return \@branches_to_use; +} + +sub least_cost_branch { + + #$from - arrayref + my ($to, $from, $transport_cost_matrix) = @_; + +# Nothing really spectacular: supply to branch, a list of potential from branches +# and find the minimum from - to value from the transport_cost_matrix + return $from->[0] if @$from == 1; + + my ($least_cost, @branch); + foreach (@$from) { + my $cell = $transport_cost_matrix->{$to}{$_}; + next if $cell->{disable_transfer}; + + my $cost = $cell->{cost}; + + unless (defined $least_cost) { + $least_cost = $cost; + push @branch, $_; + next; + } + + next if $cost > $least_cost; + + if ($cost == $least_cost) { + push @branch, $_; + next; + } + + @branch = ($_); + $least_cost = $cost; + } + + return $branch[0]; + + # XXX return a random @branch with minimum cost instead of the first one; + # return $branch[0] if @branch == 1; +} + + +1; diff --git a/admin/systempreferences.pl b/admin/systempreferences.pl index f4069ae..c0854c7 100755 --- a/admin/systempreferences.pl +++ b/admin/systempreferences.pl @@ -203,6 +203,7 @@ $tabsysprefs{DisplayClearScreenButton} = "Circulation"; $tabsysprefs{AllowAllMessageDeletion} = "Circulation"; $tabsysprefs{OverdueNoticeBcc} = "Circulation"; $tabsysprefs{OverduesBlockCirc} = "Circulation"; +$tabsysprefs{UseTransportCostMatrix} = "Circulation"; # Staff Client diff --git a/admin/transport-cost-matrix.pl b/admin/transport-cost-matrix.pl new file mode 100755 index 0000000..08865c2 --- /dev/null +++ b/admin/transport-cost-matrix.pl @@ -0,0 +1,122 @@ +#!/usr/bin/perl +# Copyright 2000-2002 Katipo Communications +# copyright 2010 BibLibre +# +# 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use strict; +use warnings; +use CGI; +use C4::Context; +use C4::Output; +use C4::Auth; +use C4::Koha; +use C4::Debug; +use C4::Branch; # GetBranches +use C4::HoldsQueue qw(TransportCostMatrix UpdateTransportCostMatrix SetUseTransportCostMatrix); + +use Data::Dumper; + +my $input = new CGI; + +my ($template, $loggedinuser, $cookie) + = get_template_and_user({template_name => "admin/transport-cost-matrix.tmpl", + query => $input, + type => "intranet", + authnotrequired => 0, + flagsrequired => {parameters => 1}, + debug => 1, + }); + +my $update = $input->param('op') eq 'set-cost-matrix'; +my $use_transport_cost_matrix = $input->param('UseTransportCostMatrix') || 0; + +my ($cost_matrix, $have_matrix); +unless ($update) { + $cost_matrix = TransportCostMatrix(); + $have_matrix = keys %$cost_matrix if $cost_matrix; + $use_transport_cost_matrix = C4::Context->preference("UseTransportCostMatrix"); +} + +my $branches = GetBranches(); +my @branchloop = map { code => $_, + name => $branches->{$_}->{'branchname'} }, + sort { $branches->{$a}->{branchname} cmp $branches->{$b}->{branchname} } + keys %$branches; +my (@branchfromloop, @cost, @errors); +foreach my $branchfrom ( @branchloop ) { + my $fromcode = $branchfrom->{code}; + + my %from_row = ( code => $fromcode, name => $branchfrom->{name} ); + foreach my $branchto ( @branchloop ) { + my $tocode = $branchto->{code}; + + my %from_to_input_def = ( code => $tocode, name => $branchto->{name} ); + push @{ $from_row{branchtoloop} }, \%from_to_input_def; + + if ($fromcode eq $tocode) { + $from_to_input_def{skip} = 1; + next; + } + + (my $from_to = "${fromcode}_${tocode}") =~ s/\W//go; + $from_to_input_def{id} = $from_to; + my $input_name = "cost_$from_to"; + my $disable_name = "disable_$from_to"; + + if ($update) { + $from_to_input_def{disabled} = 1 if $input->param($disable_name); + my $value = $from_to_input_def{value} = $input->param($input_name); + push @errors, "Invalid value for $from_row{name} -> $from_to_input_def{name}" + unless $value >= 0.0 && $value <= 1.0; + } + else { + if ($have_matrix) { + if ( my $cell = $cost_matrix->{$tocode}{$fromcode} ) { + $from_to_input_def{value} = $cell->{cost}; + $from_to_input_def{disabled} = 1 if $cell->{disable_transfer}; + } + } else { + $from_to_input_def{value} = 0.5; + } + } + } + +# die Dumper(\%from_row); + push @branchfromloop, \%from_row; +} + +if ($update && !@errors) { + my @update_recs = map { + my $from = $_->{code}; + map { frombranch => $from, tobranch => $_->{code}, cost => $_->{value}, disable_transfer => $_->{disabled} || 0 }, + grep { $_->{code} ne $from } + @{ $_->{branchtoloop} }; + } @branchfromloop; + + UpdateTransportCostMatrix(\@update_recs); + SetUseTransportCostMatrix($use_transport_cost_matrix); +} + +$template->param( + branchloop => \@branchloop, + branchfromloop => \@branchfromloop, + UseTransportCostMatrix => $use_transport_cost_matrix, +); +output_html_with_http_headers $input, $cookie, $template->output; + +exit 0; + diff --git a/circ/view_holdsqueue.pl b/circ/view_holdsqueue.pl index 4b51423..cf529f0 100755 --- a/circ/view_holdsqueue.pl +++ b/circ/view_holdsqueue.pl @@ -31,7 +31,7 @@ use C4::Biblio; use C4::Items; use C4::Koha; # GetItemTypes use C4::Branch; # GetBranches -use C4::Dates qw/format_date/; +use C4::HoldsQueue qw(GetHoldsQueueItems); my $query = new CGI; my ( $template, $loggedinuser, $cookie ) = get_template_and_user( @@ -51,6 +51,7 @@ my $branchlimit = $params->{'branchlimit'}; my $itemtypeslimit = $params->{'itemtypeslimit'}; if ( $run_report ) { + # XXX GetHoldsQueueItems() does not support $itemtypeslimit! my $items = GetHoldsQueueItems($branchlimit, $itemtypeslimit); $template->param( branch => $branchlimit, @@ -76,36 +77,5 @@ $template->param( itemtypeloop => \@itemtypesloop, ); -sub GetHoldsQueueItems { - my ($branchlimit,$itemtypelimit) = @_; - my $dbh = C4::Context->dbh; - - my @bind_params = (); - my $query = q/SELECT tmp_holdsqueue.*, biblio.author, items.ccode, items.location, items.enumchron, items.cn_sort, biblioitems.publishercode,biblio.copyrightdate,biblioitems.publicationyear,biblioitems.pages,biblioitems.size,biblioitems.publicationyear,biblioitems.isbn,items.copynumber - FROM tmp_holdsqueue - JOIN biblio USING (biblionumber) - LEFT JOIN biblioitems USING (biblionumber) - LEFT JOIN items USING ( itemnumber) - /; - if ($branchlimit) { - $query .=" WHERE tmp_holdsqueue.holdingbranch = ?"; - push @bind_params, $branchlimit; - } - $query .= " ORDER BY ccode, location, cn_sort, author, title, pickbranch, reservedate"; - my $sth = $dbh->prepare($query); - $sth->execute(@bind_params); - my $items = []; - while ( my $row = $sth->fetchrow_hashref ){ - $row->{reservedate} = format_date($row->{reservedate}); - my $record = GetMarcBiblio($row->{biblionumber}); - if ($record){ - $row->{subtitle} = GetRecordValue('subtitle',$record,'')->[0]->{subfield}; - $row->{parts} = GetRecordValue('parts',$record,'')->[0]->{subfield}; - $row->{numbers} = GetRecordValue('numbers',$record,'')->[0]->{subfield}; - } - push @$items, $row; - } - return $items; -} # writing the template output_html_with_http_headers $query, $cookie, $template->output; diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql index 67149c9..e9492f5 100644 --- a/installer/data/mysql/kohastructure.sql +++ b/installer/data/mysql/kohastructure.sql @@ -2672,6 +2672,21 @@ CREATE TABLE `fieldmapping` ( -- koha to keyword mapping ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- +-- Table structure for table `transport_cost` +-- + +DROP TABLE IF EXISTS `transport_cost`; +CREATE TABLE `transport_cost` ( + `frombranch` varchar(10) NOT NULL, + `tobranch` varchar(10) NOT NULL, + `cost` decimal(4,3) NOT NULL, + `disable_transfer` tinyint(1) NOT NULL DEFAULT 0, + CHECK ( `frombranch` <> `tobranch` ), -- a dud check, mysql does not support that + CHECK ( cost >= 0.0 AND cost <= 1.0), -- a dud check, mysql does not support that + PRIMARY KEY (`frombranch`, `tobranch`), + CONSTRAINT `transport_cost_ibfk_1` FOREIGN KEY (`frombranch`) REFERENCES `branches` (`branchcode`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `transport_cost_ibfk_2` FOREIGN KEY (`tobranch`) REFERENCES `branches` (`branchcode`) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- Table structure for table `bibliocoverimage` -- diff --git a/installer/data/mysql/sysprefs.sql b/installer/data/mysql/sysprefs.sql index 0cc79b2..08bef91 100644 --- a/installer/data/mysql/sysprefs.sql +++ b/installer/data/mysql/sysprefs.sql @@ -308,6 +308,7 @@ INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES ('TraceCompleteSubfields','0','Force subject tracings to only match complete subfields.','0','YesNo'); INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES ('UseAuthoritiesForTracings','1','Use authority record numbers for subject tracings instead of heading strings.','0','YesNo'); INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ('OPACAllowUserToChooseBranch', 1, 'Allow the user to choose the branch they want to pickup their hold from','1','YesNo'); +INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('UseTransportCostMatrix',0,"Use Transport Cost Matrix when filling holds",'','YesNo'); INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('displayFacetCount', '0', NULL, NULL, 'YesNo'); INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('maxRecordsForFacets', '20', NULL, NULL, 'Integer'); INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ('AllowPurchaseSuggestionBranchChoice', 0, 'Allow user to choose branch when making a purchase suggestion','1','YesNo'); @@ -322,6 +323,7 @@ INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('OpacHiddenItems','','This syspref allows to define custom rules for hiding specific items at opac. See docs/opac/OpacHiddenItems.txt for more informations.','','Textarea'); INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('numSearchRSSResults',50,'Specify the maximum number of results to display on a RSS page of results',NULL,'Integer'); INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ('OpacRenewalBranch','checkoutbranch','Choose how the branch for an OPAC renewal is recorded in statistics','itemhomebranch|patronhomebranch|checkoutbranch|null','Choice'); +INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('UseTransportCostMatrix',0,"Use Transport Cost Matrix when filling holds",'','YesNo'); INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES ('BasketConfirmations', '1', 'When closing or reopening a basket,', 'always ask for confirmation.|do not ask for confirmation.', 'Choice'); INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES ('MARCAuthorityControlField008', '|| aca||aabn | a|a d', NULL, NULL, 'Textarea'); INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('OpenLibraryCovers',0,'If ON Openlibrary book covers will be show',NULL,'YesNo'); diff --git a/installer/data/mysql/updatedatabase.pl b/installer/data/mysql/updatedatabase.pl index d2d9d97..ff54c46 100755 --- a/installer/data/mysql/updatedatabase.pl +++ b/installer/data/mysql/updatedatabase.pl @@ -4712,6 +4712,26 @@ if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) { SetVersion($DBversion); } +$DBversion = "3.07.00.XXX"; +if (C4::Context->preference("Version") < TransformToNum($DBversion)) { + $dbh->do("INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('UseTransportCostMatrix',0,'Use Transport Cost Matrix when filling holds','','YesNo')"); + + $dbh->do("CREATE TABLE `transport_cost` ( + `frombranch` varchar(10) NOT NULL, + `tobranch` varchar(10) NOT NULL, + `cost` decimal(4,3) NOT NULL, + `disable_transfer` tinyint(1) NOT NULL DEFAULT 0, + CHECK ( `frombranch` <> `tobranch` ), -- a dud check, mysql does not support that + CHECK ( cost >= 0.0 AND cost <= 1.0), -- a dud check, mysql does not support that + PRIMARY KEY (`frombranch`, `tobranch`), + CONSTRAINT `transport_cost_ibfk_1` FOREIGN KEY (`frombranch`) REFERENCES `branches` (`branchcode`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `transport_cost_ibfk_2` FOREIGN KEY (`tobranch`) REFERENCES `branches` (`branchcode`) ON DELETE CASCADE ON UPDATE CASCADE + ) ENGINE=InnoDB DEFAULT CHARSET=utf8"); + + print "Upgrade to $DBversion done (creating `transport_cost` table; adding UseTransportCostMatrix systempref, in circulation)\n"; + SetVersion ($DBversion); +} + =head1 FUNCTIONS =head2 DropAllForeignKeys($table) diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt index fe76ae8..9913663 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt @@ -53,6 +53,8 @@
    Define circulation and fines rules for combinations of libraries, patron categories, and item types
    Library Transfer Limits
    Limit the ability to transfer items between libraries based on the library sending, the library receiving, and the item type involved. These rules only go into effect if the preference UseBranchTransferLimits is set to ON.
    +
    Transport Cost Matrix
    +
    Define transport costs between branches
    Item Circulation Alerts
    Define rules for check-in and checkout notifications for combinations of libraries, patron categories, and item types
    diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/transport-cost-matrix.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/transport-cost-matrix.tt new file mode 100644 index 0000000..c426e16 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/transport-cost-matrix.tt @@ -0,0 +1,126 @@ +[% INCLUDE 'doc-head-open.inc' %] +Koha › Administration › Transport Cost Matrix +[% INCLUDE 'doc-head-close.inc' %] + + + + + + +[% INCLUDE 'header.inc' %] +[% INCLUDE 'cat-search.inc' %] + + + +
    + +
    +
    +
    +

    + Defining transport costs between libraries +

    +
    +
    + +

    Use Transport Cost Matrix +

    +
    +

    Costs are normalised decimal values 0 to 1, 0 being minimum (no) cost, 1 maximum.

    +

    Red cells signify no transfer allowed

    +

    Click on the cell to edit

    +
    + + + + [% FOR b IN branchloop %] + + [% END %] + + [% FOR bf IN branchfromloop %] + + + [% FOR bt IN bf.branchtoloop %] + + [% END %] + + [% END %] +
    From \ To[% b.name %]
    [% bf.name %] + [% IF bt.skip %] +   + [% ELSE %] +
    +
    [% bt.value %]
    + + [% IF bt.disabled %] + + [% END %] +
    + [% END %] +
    +
    + +
    +
    +
    +
    +
    +[% INCLUDE 'admin-menu.inc' %] +
    +
    +[% INCLUDE 'intranet-bottom.inc' %] diff --git a/misc/cronjobs/holds/build_holds_queue.pl b/misc/cronjobs/holds/build_holds_queue.pl index f01153e..9ec9825 100755 --- a/misc/cronjobs/holds/build_holds_queue.pl +++ b/misc/cronjobs/holds/build_holds_queue.pl @@ -5,7 +5,6 @@ #----------------------------------- # FIXME: add command-line options for verbosity and summary # FIXME: expand perldoc, explain intended logic -# FIXME: refactor all subroutines into C4 for testability use strict; use warnings; @@ -16,384 +15,7 @@ BEGIN { eval { require "$FindBin::Bin/../kohalib.pl" }; } -use C4::Context; -use C4::Search; -use C4::Items; -use C4::Branch; -use C4::Circulation; -use C4::Members; -use C4::Biblio; +use C4::HoldsQueue qw(CreateQueue); -use List::Util qw(shuffle); +CreateQueue(); -my $bibs_with_pending_requests = GetBibsWithPendingHoldRequests(); - -my $dbh = C4::Context->dbh; -$dbh->do("DELETE FROM tmp_holdsqueue"); # clear the old table for new info -$dbh->do("DELETE FROM hold_fill_targets"); - -my $total_bibs = 0; -my $total_requests = 0; -my $total_available_items = 0; -my $num_items_mapped = 0; - -my @branches_to_use = _get_branches_to_pull_from(); - -foreach my $biblionumber (@$bibs_with_pending_requests) { - $total_bibs++; - my $hold_requests = GetPendingHoldRequestsForBib($biblionumber); - my $available_items = GetItemsAvailableToFillHoldRequestsForBib($biblionumber, @branches_to_use); - $total_requests += scalar(@$hold_requests); - $total_available_items += scalar(@$available_items); - my $item_map = MapItemsToHoldRequests($hold_requests, $available_items, @branches_to_use); - - (defined($item_map)) or next; - - my $item_map_size = scalar(keys %$item_map); - $num_items_mapped += $item_map_size; - CreatePicklistFromItemMap($item_map); - AddToHoldTargetMap($item_map); - if (($item_map_size < scalar(@$hold_requests )) and - ($item_map_size < scalar(@$available_items))) { - # DOUBLE CHECK, but this is probably OK - unfilled item-level requests - # FIXME - #warn "unfilled requests for $biblionumber"; - #warn Dumper($hold_requests), Dumper($available_items), Dumper($item_map); - } -} - -exit 0; - -=head1 FUNCTIONS - -=head2 GetBibsWithPendingHoldRequests - - my $biblionumber_aref = GetBibsWithPendingHoldRequests(); - -Return an arrayref of the biblionumbers of all bibs -that have one or more unfilled hold requests. - -=cut - -sub GetBibsWithPendingHoldRequests { - my $dbh = C4::Context->dbh; - - my $bib_query = "SELECT DISTINCT biblionumber - FROM reserves - WHERE found IS NULL - AND priority > 0 - AND reservedate <= CURRENT_DATE()"; - my $sth = $dbh->prepare($bib_query); - - $sth->execute(); - my $biblionumbers = $sth->fetchall_arrayref(); - - return [ map { $_->[0] } @$biblionumbers ]; -} - -=head2 GetPendingHoldRequestsForBib - - my $requests = GetPendingHoldRequestsForBib($biblionumber); - -Returns an arrayref of hashrefs to pending, unfilled hold requests -on the bib identified by $biblionumber. The following keys -are present in each hashref: - - biblionumber - borrowernumber - itemnumber - priority - branchcode - reservedate - reservenotes - borrowerbranch - -The arrayref is sorted in order of increasing priority. - -=cut - -sub GetPendingHoldRequestsForBib { - my $biblionumber = shift; - - my $dbh = C4::Context->dbh; - - my $request_query = "SELECT biblionumber, borrowernumber, itemnumber, priority, reserves.branchcode, - reservedate, reservenotes, borrowers.branchcode AS borrowerbranch - FROM reserves - JOIN borrowers USING (borrowernumber) - WHERE biblionumber = ? - AND found IS NULL - AND priority > 0 - AND reservedate <= CURRENT_DATE() - ORDER BY priority"; - my $sth = $dbh->prepare($request_query); - $sth->execute($biblionumber); - - my $requests = $sth->fetchall_arrayref({}); - return $requests; - -} - -=head2 GetItemsAvailableToFillHoldRequestsForBib - - my $available_items = GetItemsAvailableToFillHoldRequestsForBib($biblionumber); - -Returns an arrayref of items available to fill hold requests -for the bib identified by C<$biblionumber>. An item is available -to fill a hold request if and only if: - - * it is not on loan - * it is not withdrawn - * it is not marked notforloan - * it is not currently in transit - * it is not lost - * it is not sitting on the hold shelf - -=cut - -sub GetItemsAvailableToFillHoldRequestsForBib { - my $biblionumber = shift; - my @branches_to_use = @_; - - my $dbh = C4::Context->dbh; - my $items_query = "SELECT itemnumber, homebranch, holdingbranch, itemtypes.itemtype AS itype - FROM items "; - - if (C4::Context->preference('item-level_itypes')) { - $items_query .= "LEFT JOIN itemtypes ON (itemtypes.itemtype = items.itype) "; - } else { - $items_query .= "JOIN biblioitems USING (biblioitemnumber) - LEFT JOIN itemtypes USING (itemtype) "; - } - $items_query .= "WHERE items.notforloan = 0 - AND holdingbranch IS NOT NULL - AND itemlost = 0 - AND wthdrawn = 0"; - $items_query .= " AND damaged = 0 " unless C4::Context->preference('AllowHoldsOnDamagedItems'); - $items_query .= " AND items.onloan IS NULL - AND (itemtypes.notforloan IS NULL OR itemtypes.notforloan = 0) - AND itemnumber NOT IN ( - SELECT itemnumber - FROM reserves - WHERE biblionumber = ? - AND itemnumber IS NOT NULL - AND (found IS NOT NULL OR priority = 0) - ) - AND items.biblionumber = ?"; - my @params = ($biblionumber, $biblionumber); - if ($#branches_to_use > -1) { - $items_query .= " AND holdingbranch IN (" . join (",", map { "?" } @branches_to_use) . ")"; - push @params, @branches_to_use; - } - my $sth = $dbh->prepare($items_query); - $sth->execute(@params); - - my $items = $sth->fetchall_arrayref({}); - $items = [ grep { my @transfers = GetTransfers($_->{itemnumber}); $#transfers == -1; } @$items ]; - map { my $rule = GetBranchItemRule($_->{homebranch}, $_->{itype}); $_->{holdallowed} = $rule->{holdallowed}; $rule->{holdallowed} != 0 } @$items; - return [ grep { $_->{holdallowed} != 0 } @$items ]; -} - -=head2 MapItemsToHoldRequests - - MapItemsToHoldRequests($hold_requests, $available_items); - -=cut - -sub MapItemsToHoldRequests { - my $hold_requests = shift; - my $available_items = shift; - my @branches_to_use = @_; - - # handle trival cases - return unless scalar(@$hold_requests) > 0; - return unless scalar(@$available_items) > 0; - - # identify item-level requests - my %specific_items_requested = map { $_->{itemnumber} => 1 } - grep { defined($_->{itemnumber}) } - @$hold_requests; - - # group available items by itemnumber - my %items_by_itemnumber = map { $_->{itemnumber} => $_ } @$available_items; - - # items already allocated - my %allocated_items = (); - - # map of items to hold requests - my %item_map = (); - - # figure out which item-level requests can be filled - my $num_items_remaining = scalar(@$available_items); - foreach my $request (@$hold_requests) { - last if $num_items_remaining == 0; - - # is this an item-level request? - if (defined($request->{itemnumber})) { - # fill it if possible; if not skip it - if (exists $items_by_itemnumber{$request->{itemnumber}} and - not exists $allocated_items{$request->{itemnumber}}) { - $item_map{$request->{itemnumber}} = { - borrowernumber => $request->{borrowernumber}, - biblionumber => $request->{biblionumber}, - holdingbranch => $items_by_itemnumber{$request->{itemnumber}}->{holdingbranch}, - pickup_branch => $request->{branchcode}, - item_level => 1, - reservedate => $request->{reservedate}, - reservenotes => $request->{reservenotes}, - }; - $allocated_items{$request->{itemnumber}}++; - $num_items_remaining--; - } - } else { - # it's title-level request that will take up one item - $num_items_remaining--; - } - } - - # group available items by branch - my %items_by_branch = (); - foreach my $item (@$available_items) { - push @{ $items_by_branch{ $item->{holdingbranch} } }, $item unless exists $allocated_items{ $item->{itemnumber} }; - } - - # now handle the title-level requests - $num_items_remaining = scalar(@$available_items) - scalar(keys %allocated_items); - foreach my $request (@$hold_requests) { - last if $num_items_remaining <= 0; - next if defined($request->{itemnumber}); # already handled these - - # look for local match first - my $pickup_branch = $request->{branchcode}; - if (exists $items_by_branch{$pickup_branch} and - not ($items_by_branch{$pickup_branch}->[0]->{holdallowed} == 1 and - $request->{borrowerbranch} ne $items_by_branch{$pickup_branch}->[0]->{homebranch}) - ) { - my $item = pop @{ $items_by_branch{$pickup_branch} }; - delete $items_by_branch{$pickup_branch} if scalar(@{ $items_by_branch{$pickup_branch} }) == 0; - $item_map{$item->{itemnumber}} = { - borrowernumber => $request->{borrowernumber}, - biblionumber => $request->{biblionumber}, - holdingbranch => $pickup_branch, - pickup_branch => $pickup_branch, - item_level => 0, - reservedate => $request->{reservedate}, - reservenotes => $request->{reservenotes}, - }; - $num_items_remaining--; - } else { - my @pull_branches = (); - if ($#branches_to_use > -1) { - @pull_branches = @branches_to_use; - } else { - @pull_branches = sort keys %items_by_branch; - } - foreach my $branch (@pull_branches) { - next unless exists $items_by_branch{$branch} and - not ($items_by_branch{$branch}->[0]->{holdallowed} == 1 and - $request->{borrowerbranch} ne $items_by_branch{$branch}->[0]->{homebranch}); - my $item = pop @{ $items_by_branch{$branch} }; - delete $items_by_branch{$branch} if scalar(@{ $items_by_branch{$branch} }) == 0; - $item_map{$item->{itemnumber}} = { - borrowernumber => $request->{borrowernumber}, - biblionumber => $request->{biblionumber}, - holdingbranch => $branch, - pickup_branch => $pickup_branch, - item_level => 0, - reservedate => $request->{reservedate}, - reservenotes => $request->{reservenotes}, - }; - $num_items_remaining--; - last; - } - } - } - return \%item_map; -} - -=head2 CreatePickListFromItemMap - -=cut - -sub CreatePicklistFromItemMap { - my $item_map = shift; - - my $dbh = C4::Context->dbh; - - my $sth_load=$dbh->prepare(" - INSERT INTO tmp_holdsqueue (biblionumber,itemnumber,barcode,surname,firstname,phone,borrowernumber, - cardnumber,reservedate,title, itemcallnumber, - holdingbranch,pickbranch,notes, item_level_request) - VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) - "); - - foreach my $itemnumber (sort keys %$item_map) { - my $mapped_item = $item_map->{$itemnumber}; - my $biblionumber = $mapped_item->{biblionumber}; - my $borrowernumber = $mapped_item->{borrowernumber}; - my $pickbranch = $mapped_item->{pickup_branch}; - my $holdingbranch = $mapped_item->{holdingbranch}; - my $reservedate = $mapped_item->{reservedate}; - my $reservenotes = $mapped_item->{reservenotes}; - my $item_level = $mapped_item->{item_level}; - - my $item = GetItem($itemnumber); - my $barcode = $item->{barcode}; - my $itemcallnumber = $item->{itemcallnumber}; - - my $borrower = GetMember('borrowernumber'=>$borrowernumber); - my $cardnumber = $borrower->{'cardnumber'}; - my $surname = $borrower->{'surname'}; - my $firstname = $borrower->{'firstname'}; - my $phone = $borrower->{'phone'}; - - my $bib = GetBiblioData($biblionumber); - my $title = $bib->{title}; - - $sth_load->execute($biblionumber, $itemnumber, $barcode, $surname, $firstname, $phone, $borrowernumber, - $cardnumber, $reservedate, $title, $itemcallnumber, - $holdingbranch, $pickbranch, $reservenotes, $item_level); - } -} - -=head2 AddToHoldTargetMap - -=cut - -sub AddToHoldTargetMap { - my $item_map = shift; - - my $dbh = C4::Context->dbh; - - my $insert_sql = q( - INSERT INTO hold_fill_targets (borrowernumber, biblionumber, itemnumber, source_branchcode, item_level_request) - VALUES (?, ?, ?, ?, ?) - ); - my $sth_insert = $dbh->prepare($insert_sql); - - foreach my $itemnumber (keys %$item_map) { - my $mapped_item = $item_map->{$itemnumber}; - $sth_insert->execute($mapped_item->{borrowernumber}, $mapped_item->{biblionumber}, $itemnumber, - $mapped_item->{holdingbranch}, $mapped_item->{item_level}); - } -} - -=head2 _get_branches_to_pull_from - -Query system preferences to get ordered list of -branches to use to fill hold requests. - -=cut - -sub _get_branches_to_pull_from { - my @branches_to_use = (); - - my $static_branch_list = C4::Context->preference("StaticHoldsQueueWeight"); - if ($static_branch_list) { - @branches_to_use = map { s/^\s+//; s/\s+$//; $_; } split /,/, $static_branch_list; - } - - @branches_to_use = shuffle(@branches_to_use) if C4::Context->preference("RandomizeHoldsQueueWeight"); - - return @branches_to_use; -} diff --git a/t/db_dependent/HoldsQueue.t b/t/db_dependent/HoldsQueue.t new file mode 100755 index 0000000..6cce4d9 --- /dev/null +++ b/t/db_dependent/HoldsQueue.t @@ -0,0 +1,161 @@ +#!/usr/bin/perl + +# Test C4::HoldsQueue::CreateQueue() for both transport cost matrix +# and StaticHoldsQueueWeight array (no RandomizeHoldsQueueWeight, no point) +# Wraps tests in transaction that's rolled back, so no data is destroyed +# MySQL WARNING: This makes sense only if your tables are InnoDB, otherwise +# transactions are not supported and mess is left behind + +use strict; +use warnings; +use C4::Context; + +use Data::Dumper; + +use Test::More tests => 15; + +BEGIN { + use FindBin; + use lib $FindBin::Bin; + use_ok('C4::Reserves'); + use_ok('C4::HoldsQueue'); +} + +my $TITLE = "Test Holds Queue XXX"; +# Pick a plausible borrower. Easier than creating one. +my $BORROWER_QRY = <dbh; +my $borrower = $dbh->selectrow_hashref($BORROWER_QRY); +my $borrowernumber = $borrower->{borrowernumber}; +# Set special (for this test) branches +my $borrower_branchcode = $borrower->{branchcode}; +my @other_branches = grep { $_ ne $borrower_branchcode } @{ $dbh->selectcol_arrayref("SELECT branchcode FROM branches") }; +my $least_cost_branch_code = pop @other_branches + or BAIL_OUT("No point testing only one branch..."); + +# Start transaction +$dbh->{AutoCommit} = 0; +$dbh->{RaiseError} = 1; + +#Set up the stage +# Sysprefs and cost matrix +$dbh->do("UPDATE systempreferences SET value = ? WHERE variable = 'StaticHoldsQueueWeight'", undef, + join( ',', @other_branches, $borrower_branchcode, $least_cost_branch_code)); +$dbh->do("UPDATE systempreferences SET value = '0' WHERE variable = 'RandomizeHoldsQueueWeight'"); + +$dbh->do("DELETE FROM transport_cost"); +my $transport_cost_insert_sth = $dbh->prepare("insert into transport_cost (frombranch, tobranch, cost) values (?, ?, ?)"); +# Favour $least_cost_branch_code +$transport_cost_insert_sth->execute($borrower_branchcode, $least_cost_branch_code, 0.2); +$transport_cost_insert_sth->execute($least_cost_branch_code, $borrower_branchcode, 0.2); +my @b = @other_branches; +while ( my $b1 = shift @b ) { + foreach my $b2 ($borrower_branchcode, $least_cost_branch_code, @b) { + $transport_cost_insert_sth->execute($b1, $b2, 0.5); + $transport_cost_insert_sth->execute($b2, $b1, 0.5); + } +} + + +# Loanable items - all possible combinations of homebranch and holdingbranch +$dbh->do("INSERT INTO biblio (frameworkcode, author, title, datecreated) + VALUES ('SER', 'Koha test', '$TITLE', '2011-02-01')"); +my $biblionumber = $dbh->selectrow_array("SELECT biblionumber FROM biblio WHERE title = '$TITLE'") + or BAIL_OUT("Cannot find newly created biblio record"); +$dbh->do("INSERT INTO biblioitems (biblionumber, marcxml) + VALUES ($biblionumber, '')"); +my $biblioitemnumber = $dbh->selectrow_array("SELECT biblioitemnumber FROM biblioitems WHERE biblionumber = $biblionumber") + or BAIL_OUT("Cannot find newly created biblioitems record"); + +my $items_insert_sth = $dbh->prepare("INSERT INTO items (biblionumber, biblioitemnumber, barcode, homebranch, holdingbranch, notforloan, damaged, itemlost, wthdrawn, onloan) + VALUES ($biblionumber, $biblioitemnumber, ?, ?, ?, 0, 0, 0, 0, NULL)"); # CURRENT_DATE - 3)"); +my $first_barcode = int(rand(1000000000000)); # XXX +my $barcode = $first_barcode; +foreach ( $borrower_branchcode, $least_cost_branch_code, @other_branches ) { + $items_insert_sth->execute($barcode++, $borrower_branchcode, $_); + $items_insert_sth->execute($barcode++, $_, $_); + $items_insert_sth->execute($barcode++, $_, $borrower_branchcode); +} + +# Remove existing reserves, makes debugging easier +$dbh->do("DELETE FROM reserves"); +my $constraint = undef; +my $bibitems = undef; +my $priority = 1; +# Make a reserve +AddReserve ( $borrower_branchcode, $borrowernumber, $biblionumber, $constraint, $bibitems, $priority ); +# $resdate, $expdate, $notes, $title, $checkitem, $found +$dbh->do("UPDATE reserves SET reservedate = reservedate - 1"); + +# Tests +my $use_cost_matrix_sth = $dbh->prepare("UPDATE systempreferences SET value = ? WHERE variable = 'UseTransportCostMatrix'"); +my $test_sth = $dbh->prepare("SELECT * FROM hold_fill_targets + JOIN tmp_holdsqueue USING (borrowernumber, biblionumber, itemnumber) + JOIN items USING (itemnumber) + WHERE borrowernumber = $borrowernumber"); + +# We have a book available homed in borrower branch +test_queue ('take from homebranch', 0, $borrower_branchcode, $borrower_branchcode); +test_queue ('take from homebranch', 1, $borrower_branchcode, $borrower_branchcode); + +$dbh->do("DELETE FROM tmp_holdsqueue"); +$dbh->do("DELETE FROM hold_fill_targets"); +$dbh->do("DELETE FROM issues WHERE itemnumber IN (SELECT itemnumber FROM items WHERE homebranch = '$borrower_branchcode')"); +$dbh->do("DELETE FROM items WHERE homebranch = '$borrower_branchcode'"); +# We have a book available held in borrower branch +test_queue ('take from holdingbranch', 0, $borrower_branchcode, $borrower_branchcode); +test_queue ('take from holdingbranch', 1, $borrower_branchcode, $borrower_branchcode); + +$dbh->do("DELETE FROM tmp_holdsqueue"); +$dbh->do("DELETE FROM hold_fill_targets"); +$dbh->do("DELETE FROM issues WHERE itemnumber IN (SELECT itemnumber FROM items WHERE holdingbranch = '$borrower_branchcode')"); +$dbh->do("DELETE FROM items WHERE holdingbranch = '$borrower_branchcode'"); +# No book available in borrower branch, pick according to the rules +# Frst branch from StaticHoldsQueueWeight +test_queue ('take from lowest cost branch', 0, $borrower_branchcode, $other_branches[0]); +test_queue ('take from lowest cost branch', 1, $borrower_branchcode, $least_cost_branch_code); +my $queue = C4::HoldsQueue::GetHoldsQueueItems($least_cost_branch_code) || []; +my $queue_item = $queue->[0]; +ok( $queue_item + && $queue_item->{pickbranch} eq $borrower_branchcode + && $queue_item->{holdingbranch} eq $least_cost_branch_code, "GetHoldsQueueItems" ) + or diag( "Expected item for pick $borrower_branchcode, hold $least_cost_branch_code, got ".Dumper($queue_item) ); + +# XXX All this tests are for borrower branch pick-up. +# Maybe needs expanding to homebranch or holdingbranch pick-up. + +# Cleanup +$dbh->rollback; + +exit; + +sub test_queue { + my ($test_name, $use_cost_matrix, $pick_branch, $hold_branch) = @_; + + $test_name = "$test_name (".($use_cost_matrix ? "" : "don't")." use cost matrix)"; + + $use_cost_matrix_sth->execute($use_cost_matrix); + C4::Context->_flush_preferences(); + C4::HoldsQueue::CreateQueue(); + + my $results = $dbh->selectall_arrayref($test_sth, { Slice => {} }); # should be only one + my $r = $results->[0]; + + my $ok = is( $r->{pickbranch}, $pick_branch, "$test_name pick up branch"); + $ok &&= is( $r->{holdingbranch}, $hold_branch, "$test_name holding branch") + if $hold_branch; + + diag( "Wrong pick-up/hold: ". Dumper ($pick_branch,, $hold_branch, map dump_records($_), qw(reserves hold_fill_targets tmp_holdsqueue)) ) + unless $ok; +} + +sub dump_records { + my ($tablename) = @_; + return $dbh->selectall_arrayref("SELECT * from $tablename where borrowernumber = ?", { Slice => {} }, $borrowernumber); +} + + -- 1.6.5 From jonathan.druart at biblibre.com Wed Feb 22 10:32:57 2012 From: jonathan.druart at biblibre.com (Jonathan Druart) Date: Wed, 22 Feb 2012 10:32:57 +0100 Subject: [Koha-patches] [PATCH 1/1] Bug 7291: Adds new field aqbooksellers.deliverytime Message-ID: <1329903178-7878-1-git-send-email-jonathan.druart@biblibre.com> New field deliverytime in aqbooksellers table. It is an estimated delivery time for orders (in days). You can set this delay on the supplier modification page. It is used in the late orders search. The order estimated date is the aqbasket.closedate + aqbooksellers.deliverytime If you set a delay, the query check if closedate <= today - delay If you set a "delivery time from" and a "delivery time to", the query check if $delivery_time_from <= aqbooksellers.deliverytime is not NULL and if closedate + deliverytime >= $delivery_time_to if there is not a time_to then $delivery_time_to = the current date. --- C4/Acquisition.pm | 28 ++++++++- C4/Bookseller.pm | 61 +++++++++++++++----- acqui/basket.pl | 11 ++++ acqui/lateorders.pl | 21 +++++-- acqui/supplier.pl | 2 + acqui/updatesupplier.pl | 1 + installer/data/mysql/kohastructure.sql | 1 + installer/data/mysql/updatedatabase.pl | 7 ++ .../intranet-tmpl/prog/en/modules/acqui/basket.tt | 2 + .../prog/en/modules/acqui/lateorders.tt | 41 +++++++++++++- .../prog/en/modules/acqui/supplier.tt | 8 +++ 11 files changed, 157 insertions(+), 26 deletions(-) diff --git a/C4/Acquisition.pm b/C4/Acquisition.pm index 0a96a02..c6220c1 100644 --- a/C4/Acquisition.pm +++ b/C4/Acquisition.pm @@ -1438,13 +1438,15 @@ sub GetLateOrders { my $delay = shift; my $supplierid = shift; my $branch = shift; + my $estimateddeliverydatefrom = shift; + my $estimateddeliverydateto = shift; my $dbh = C4::Context->dbh; #BEWARE, order of parenthesis and LEFT JOIN is important for speed my $dbdriver = C4::Context->config("db_scheme") || "mysql"; - my @query_params = ($delay); # delay is the first argument regardless + my @query_params = (); my $select = " SELECT aqbasket.basketno, aqorders.ordernumber, @@ -1460,6 +1462,7 @@ sub GetLateOrders { biblio.author, biblio.title, biblioitems.publishercode AS publisher, biblioitems.publicationyear, + ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) AS estimateddeliverydate, "; my $from = " FROM @@ -1473,6 +1476,7 @@ sub GetLateOrders { OR datereceived IS NULL OR aqorders.quantityreceived < aqorders.quantity ) + AND aqbasket.closedate IS NOT NULL AND (aqorders.datecancellationprinted IS NULL OR aqorders.datecancellationprinted='0000-00-00') "; my $having = ""; @@ -1482,7 +1486,10 @@ sub GetLateOrders { (aqorders.quantity - IFNULL(aqorders.quantityreceived,0)) * aqorders.rrp AS subtotal, DATEDIFF(CURDATE( ),closedate) AS latesince "; - $from .= " AND (closedate <= DATE_SUB(CURDATE( ),INTERVAL ? DAY)) "; + if ( defined $delay ) { + $from .= " AND (closedate <= DATE_SUB(CURDATE( ),INTERVAL ? DAY)) " ; + push @query_params, $delay; + } $having = " HAVING quantity <> 0 AND unitpricesupplier <> 0 @@ -1495,7 +1502,10 @@ sub GetLateOrders { aqorders.quantity * aqorders.rrp AS subtotal, (CURDATE - closedate) AS latesince "; - $from .= " AND (closedate <= (CURDATE -(INTERVAL ? DAY)) "; + if ( defined $delay ) { + $from .= " AND (closedate <= (CURDATE -(INTERVAL ? DAY)) "; + push @query_params, $delay; + } } if (defined $supplierid) { $from .= ' AND aqbasket.booksellerid = ? '; @@ -1505,6 +1515,18 @@ sub GetLateOrders { $from .= ' AND borrowers.branchcode LIKE ? '; push @query_params, $branch; } + if ( defined $estimateddeliverydatefrom ) { + $from .= ' + AND aqbooksellers.deliverytime IS NOT NULL + AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) >= ?'; + push @query_params, $estimateddeliverydatefrom; + } + if ( defined $estimateddeliverydatefrom and defined $estimateddeliverydateto ) { + $from .= ' AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) <= ?'; + push @query_params, $estimateddeliverydateto; + } elsif ( defined $estimateddeliverydatefrom ) { + $from .= ' AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) <= CURDATE()'; + } if (C4::Context->preference("IndependantBranches") && C4::Context->userenv && C4::Context->userenv->{flags} != 1 ) { diff --git a/C4/Bookseller.pm b/C4/Bookseller.pm index 6a91f99..f4db133 100644 --- a/C4/Bookseller.pm +++ b/C4/Bookseller.pm @@ -99,19 +99,48 @@ Searches for suppliers with late orders. =cut sub GetBooksellersWithLateOrders { - my $delay = shift; - my $dbh = C4::Context->dbh; - - # TODO delay should be verified - my $query_string = - "SELECT DISTINCT aqbasket.booksellerid, aqbooksellers.name - FROM aqorders LEFT JOIN aqbasket ON aqorders.basketno=aqbasket.basketno - LEFT JOIN aqbooksellers ON aqbasket.booksellerid = aqbooksellers.id - WHERE (closedate < DATE_SUB(CURDATE( ),INTERVAL $delay DAY) - AND (datereceived = '' OR datereceived IS NULL))"; - - my $sth = $dbh->prepare($query_string); - $sth->execute; + my ( $delay, $branch, $estimateddeliverydatefrom, $estimateddeliverydateto ) = @_; # FIXME: Branch argument unused. + 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 @query_params = (); + my $dbdriver = C4::Context->config("db_scheme") || "mysql"; + $strsth = " + SELECT DISTINCT aqbasket.booksellerid, aqbooksellers.name + FROM aqorders LEFT JOIN aqbasket ON aqorders.basketno=aqbasket.basketno + LEFT JOIN aqbooksellers ON aqbasket.booksellerid = aqbooksellers.id + WHERE + ( datereceived = '' + OR datereceived IS NULL + OR aqorders.quantityreceived < aqorders.quantity + ) + AND aqorders.rrp <> 0 + AND aqorders.ecost <> 0 + AND aqorders.quantity - IFNULL(aqorders.quantityreceived,0) <> 0 + AND aqbasket.closedate IS NOT NULL + "; + if ( defined $delay ) { + $strsth .= " AND (closedate <= DATE_SUB(CURDATE( ),INTERVAL ? DAY)) "; + push @query_params, $delay; + } + if ( defined $estimateddeliverydatefrom ) { + $strsth .= ' + AND aqbooksellers.deliverytime IS NOT NULL + AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) >= ?'; + push @query_params, $estimateddeliverydatefrom; + } + if ( defined $estimateddeliverydatefrom and defined $estimateddeliverydateto ) { + $strsth .= ' AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) <= ?'; + push @query_params, $estimateddeliverydateto; + } elsif ( defined $estimateddeliverydatefrom ) { + $strsth .= ' AND ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) <= CURDATE()'; + } + + my $sth = $dbh->prepare($strsth); + $sth->execute( @query_params ); my %supplierlist; while ( my ( $id, $name ) = $sth->fetchrow ) { $supplierlist{$id} = $name; @@ -198,7 +227,7 @@ sub ModBookseller { contphone=?,contfax=?,contaltphone=?,contemail=?, contnotes=?,active=?,listprice=?, invoiceprice=?, gstreg=?,listincgst=?,invoiceincgst=?, - discount=?,notes=?,gstrate=? + discount=?,notes=?,gstrate=?,deliverytime=? WHERE id=?'; my $sth = $dbh->prepare($query); $sth->execute( @@ -215,7 +244,9 @@ sub ModBookseller { $data->{'invoiceprice'}, $data->{'gstreg'}, $data->{'listincgst'}, $data->{'invoiceincgst'}, $data->{'discount'}, $data->{'notes'}, - $data->{'gstrate'}, $data->{'id'} + $data->{'gstrate'}, + $data->{deliverytime}, + $data->{'id'} ); return; } diff --git a/acqui/basket.pl b/acqui/basket.pl index 7864fee..163c65d 100755 --- a/acqui/basket.pl +++ b/acqui/basket.pl @@ -35,6 +35,7 @@ use C4::Biblio; use C4::Members qw/GetMember/; #needed for permissions checking for changing basketgroup of a basket use C4::Items; use C4::Suggestions; +use Date::Calc qw/Add_Delta_Days/; =head1 NAME @@ -214,6 +215,15 @@ if ( $op eq 'delete_confirm' ) { } unshift( @$basketgroups, \%emptygroup ); } + + # if the basket is closed, calculate estimated delivery date + my $estimateddeliverydate; + if( $basket->{closedate} ) { + my ($year, $month, $day) = ($basket->{closedate} =~ /(\d+)-(\d+)-(\d+)/); + ($year, $month, $day) = Add_Delta_Days($year, $month, $day, $bookseller->{deliverytime}); + $estimateddeliverydate = "$year-$month-$day"; + } + # if new basket, pre-fill infos $basket->{creationdate} = "" unless ( $basket->{creationdate} ); $basket->{authorisedby} = $loggedinuser unless ( $basket->{authorisedby} ); @@ -368,6 +378,7 @@ my $total_est_gste; authorisedby => $basket->{authorisedby}, authorisedbyname => $basket->{authorisedbyname}, closedate => C4::Dates->new($basket->{closedate},'iso')->output, + estimateddeliverydate => C4::Dates->new( $estimateddeliverydate, 'iso' )->output, active => $bookseller->{'active'}, booksellerid => $bookseller->{'id'}, name => $bookseller->{'name'}, diff --git a/acqui/lateorders.pl b/acqui/lateorders.pl index 86b1300..913d121 100755 --- a/acqui/lateorders.pl +++ b/acqui/lateorders.pl @@ -66,14 +66,14 @@ my ($template, $loggedinuser, $cookie) = get_template_and_user({ my $booksellerid = $input->param('booksellerid') || undef; # we don't want "" or 0 my $delay = $input->param('delay'); +my $estimateddeliverydatefrom = $input->param('estimateddeliverydatefrom'); +my $estimateddeliverydateto = $input->param('estimateddeliverydateto'); my $branch = $input->param('branch'); my $op = $input->param('op'); my @errors = (); -$delay = 30 unless defined $delay; -unless ($delay =~ /^\d{1,3}$/) { - push @errors, {delay_digits => 1, bad_delay => $delay}; - $delay = 30; #default value for delay +if ( defined $delay and not $delay =~ /^\d{1,3}$/ ) { + push @errors, {delay_digits => 1, bad_delay => $delay}; } if ($op and $op eq "send_alert"){ @@ -92,7 +92,13 @@ if ($op and $op eq "send_alert"){ } } -my %supplierlist = GetBooksellersWithLateOrders($delay); +my %supplierlist = GetBooksellersWithLateOrders( + $delay, + $branch, + C4::Dates->new($estimateddeliverydatefrom)->output("iso"), + C4::Dates->new($estimateddeliverydateto)->output("iso") +); + my (@sloopy); # supplier loop foreach (keys %supplierlist){ push @sloopy, (($booksellerid and $booksellerid eq $_ ) ? @@ -104,7 +110,7 @@ $template->param(SUPPLIER_LOOP => \@sloopy); $template->param(Supplier=>$supplierlist{$booksellerid}) if ($booksellerid); $template->param(booksellerid=>$booksellerid) if ($booksellerid); -my @lateorders = GetLateOrders($delay,$booksellerid,$branch); +my @lateorders = GetLateOrders( $delay, $booksellerid, $branch, $estimateddeliverydatefrom, $estimateddeliverydateto ); my $total; foreach (@lateorders){ @@ -122,7 +128,10 @@ $template->param(ERROR_LOOP => \@errors) if (@errors); $template->param( lateorders => \@lateorders, delay => $delay, + estimateddeliverydatefrom => $estimateddeliverydatefrom, + estimateddeliverydateto => $estimateddeliverydateto, total => $total, intranetcolorstylesheet => C4::Context->preference("intranetcolorstylesheet"), + DHTMLcalendar_dateformat => C4::Dates->DHTMLcalendar(), ); output_html_with_http_headers $input, $cookie, $template->output; diff --git a/acqui/supplier.pl b/acqui/supplier.pl index 8896b3b..f533a80 100755 --- a/acqui/supplier.pl +++ b/acqui/supplier.pl @@ -109,6 +109,7 @@ if ( $op eq 'display' ) { listincgst => $supplier->{'listincgst'}, invoiceincgst => $supplier->{'invoiceincgst'}, discount => $supplier->{'discount'}, + deliverytime => $supplier->{deliverytime}, invoiceprice => $supplier->{'invoiceprice'}, listprice => $supplier->{'listprice'}, GST => $tax_rate, @@ -171,6 +172,7 @@ if ( $op eq 'display' ) { invoiceincgst => $supplier->{'invoiceincgst'}, gstrate => $gstrate, discount => $supplier->{'discount'}, + deliverytime => $supplier->{deliverytime}, loop_currency => $loop_currency, GST => $tax_rate, enter => 1, diff --git a/acqui/updatesupplier.pl b/acqui/updatesupplier.pl index 3e79362..81136d7 100755 --- a/acqui/updatesupplier.pl +++ b/acqui/updatesupplier.pl @@ -107,6 +107,7 @@ if ($gstrate eq '') { $data{'gstrate'} = $input->param('gstrate')/100; } $data{'discount'}=$input->param('discount'); +$data{deliverytime} = $input->param('deliverytime'); $data{'active'}=$input->param('status'); if($data{'name'}) { if ($data{'booksellerid'}){ diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql index 67149c9d..89cb71d 100644 --- a/installer/data/mysql/kohastructure.sql +++ b/installer/data/mysql/kohastructure.sql @@ -2496,6 +2496,7 @@ CREATE TABLE `aqbooksellers` ( -- information about the vendors listed in acquis `gstrate` decimal(6,4) default NULL, -- the tax rate the library is charged `discount` float(6,4) default NULL, -- discount offered on all items ordered from this vendor `fax` varchar(50) default NULL, -- vendor fax number + `deliverytime` int(11) default NULL, -- vendor delivery time PRIMARY KEY (`id`), KEY `listprice` (`listprice`), KEY `invoiceprice` (`invoiceprice`), diff --git a/installer/data/mysql/updatedatabase.pl b/installer/data/mysql/updatedatabase.pl index d2d9d97..32b027f 100755 --- a/installer/data/mysql/updatedatabase.pl +++ b/installer/data/mysql/updatedatabase.pl @@ -4712,6 +4712,13 @@ if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) { SetVersion($DBversion); } +$DBversion = "3.07.00.XXX"; +if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) { + $dbh->do("ALTER TABLE aqbooksellers ADD deliverytime INT DEFAULT NULL"); + print "Upgrade to $DBversion done (Add deliverytime field in aqbooksellers table)"; + SetVersion($DBversion); +} + =head1 FUNCTIONS =head2 DropAllForeignKeys($table) diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/basket.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/basket.tt index 59f647c..b77bd26 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/basket.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/basket.tt @@ -1,3 +1,4 @@ +[% USE KohaDates %] [% INCLUDE 'doc-head-open.inc' %] Koha › Acquisitions › [% UNLESS ( basketno ) %]New [% END %][% IF ( delete_confirm ) %]Delete [% END %]Basket [% basketname|html %] ([% basketno %]) for [% name|html %] [% INCLUDE 'doc-head-close.inc' %] @@ -180,6 +181,7 @@ [% IF ( authorisedbyname ) %]
  • Managed by: [% authorisedbyname %]
  • [% END %] [% IF ( creationdate ) %]
  • Opened on: [% creationdate %]
  • [% END %] [% IF ( closedate ) %]
  • Closed on: [% closedate %]
  • [% END %] + [% IF ( estimateddeliverydate ) %]
  • Estimated delivery date: [% estimateddeliverydate | $KohaDates %]
  • [% END %]
    diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/lateorders.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/lateorders.tt index cdb8711..1495215 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/lateorders.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/lateorders.tt @@ -1,7 +1,9 @@ +[% USE KohaDates %] [% INCLUDE 'doc-head-open.inc' %] Koha › Acquisitions › Late orders [% INCLUDE 'doc-head-close.inc' %] +[% INCLUDE 'calendar.inc' %] +
    [% INCLUDE 'date-format.inc' %]
    + +
  • %
  • % (leave blank for default tax of [% default_gst_rate %]%)
  • +
  • + + days +
  • @@ -197,6 +201,10 @@ if (f.company.value == "") { [% discount %] %

    Tax rate: [% GST %]%[% UNLESS ( default_tax ) %] (default)[% END %]

    + [% IF deliverytime.defined %] +

    Delivery time: + [% deliverytime %] days

    + [% END %] [% IF ( notes ) %]

    Notes: [% notes %]

    [% END %] -- 1.7.7.3 From jonathan.druart at biblibre.com Wed Feb 22 15:39:40 2012 From: jonathan.druart at biblibre.com (Jonathan Druart) Date: Wed, 22 Feb 2012 15:39:40 +0100 Subject: [Koha-patches] =?utf-8?q?=5BPATCH_1/1=5D_Bug_7577=3A_Adds_a_displ?= =?utf-8?q?ay_page_for_suggestions?= Message-ID: <1329921580-20859-1-git-send-email-jonathan.druart@biblibre.com> --- .../prog/en/modules/acqui/neworderempty.tt | 2 +- .../prog/en/modules/acqui/orderreceive.tt | 2 +- .../intranet-tmpl/prog/en/modules/acqui/parcel.tt | 4 +- .../prog/en/modules/suggestion/suggestion.tt | 141 ++++++++++++++++++-- suggestion/suggestion.pl | 17 ++- 5 files changed, 148 insertions(+), 18 deletions(-) diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/neworderempty.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/neworderempty.tt index a27d151..e6464f2 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/neworderempty.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/neworderempty.tt @@ -326,7 +326,7 @@ $(document).ready(function()
    1. Suggested by: - [% surnamesuggestedby %][% IF ( firstnamesuggestedby ) %],?[% firstnamesuggestedby %][% END %] (suggestion #[% suggestionid %]) + [% surnamesuggestedby %][% IF ( firstnamesuggestedby ) %],?[% firstnamesuggestedby %][% END %] (suggestion #[% suggestionid %])
    diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/orderreceive.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/orderreceive.tt index e238278..3eb3e23 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/orderreceive.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/orderreceive.tt @@ -42,7 +42,7 @@
    1. Suggested by: - [% surnamesuggestedby %][% IF ( firstnamesuggestedby ) %],?[% firstnamesuggestedby %][% END %] (suggestion #[% suggestionid %]) + [% surnamesuggestedby %][% IF ( firstnamesuggestedby ) %],?[% firstnamesuggestedby %][% END %] (suggestion #[% suggestionid %])
    diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/parcel.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/parcel.tt index afc9b65..786c5be 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/parcel.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/parcel.tt @@ -244,7 +244,7 @@ [% IF ( loop_order.suggestionid ) %]
    Suggested by: [% loop_order.surnamesuggestedby %][% IF ( loop_order.firstnamesuggestedby ) %],?[% loop_order.firstnamesuggestedby %] [% END %] - (suggestion #[% loop_order.suggestionid %]) + (suggestion #[% loop_order.suggestionid %]) [% END %] MARC | Card @@ -369,7 +369,7 @@ [% IF ( loop_receive.suggestionid ) %]
    Suggested by: [% loop_receive.surnamesuggestedby %][% IF ( loop_receive.firstnamesuggestedby ) %],?[% loop_receive.firstnamesuggestedby %] [% END %] - (suggestion #[% loop_receive.suggestionid %]) + (suggestion #[% loop_receive.suggestionid %]) [% END %] MARC | Card diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/suggestion/suggestion.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/suggestion/suggestion.tt index 47ee96a..1f72e4f 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/suggestion/suggestion.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/suggestion/suggestion.tt @@ -1,5 +1,19 @@ -[% INCLUDE 'doc-head-open.inc' %]Koha › Acquisitions › -[% IF ( op_save ) %][% IF ( suttesionid ) %]Edit purchase suggestion #[% suggestionid %][% ELSE %]Enter a new purchase suggestion[% END %][% ELSE %]Suggestions Management[% END %] +[% INCLUDE 'doc-head-open.inc' %] +Koha › Acquisitions › + [% IF ( op_save ) %] + [% IF ( suggestionid) %] + [% IF ( op == 'show' ) %] + Show purchase suggestion #[% suggestionid %] + [% ELSE %] + Edit purchase suggestion #[% suggestionid %] + [% END %] + [% ELSE %] + Enter a new purchase suggestion + [% END %] + [% ELSE %] + Suggestions Management + [% END %] + [% INCLUDE 'doc-head-close.inc' %] [% INCLUDE 'calendar.inc' %] [% IF ( op_else ) %] @@ -91,7 +105,114 @@ $(document).ready(function() { calcNewsuggTotal(); }); [% INCLUDE 'header.inc' %] [% INCLUDE 'cat-search.inc' %] - + + +[% IF ( op == 'show' ) %] +
    +
    +
    +
    + +
    + Bibliographic information +
      +
    1. [% title |html %]
    2. +
    3. [% author %]
    4. +
    5. [% copyrightdate %]
    6. +
    7. [% isbn %]
    8. +
    9. [% publishercode %]
    10. +
    11. [% place %]
    12. +
    13. [% collectiontitle %]
    14. +
    15. + [% FOREACH itemtypeloo IN itemtypeloop %] + [% IF ( itemtypeloo.selected ) %][% itemtypeloo.description %][% END %] + [% END %] +
    16. + [% IF ( patron_reason_loop ) %] +
    17. + [% FOREACH patron_reason_loo IN patron_reason_loop %] + [% IF ( patron_reason_loo.selected ) %][% patron_reason_loo.lib %][% END %] + [% END %] +
    18. + [% END %] +
    19. [% note %]
    20. +
    +
    +
    Suggestion management +
      +
    1. + + [% IF ( STATUS == 'ASKED' ) %]Pending + [% ELSIF ( STATUS == 'ACCEPTED' ) %]Accepted + [% ELSIF ( STATUS == 'CHECKED' ) %]Checked + [% ELSIF ( STATUS == 'REJECTED' ) %]Rejected + [% ELSE %]No Status + [% END %] +
    2. +
    3. + + + + + + + + + + + + + + + + + + + +
       DateBy
      [% suggesteddate %][% IF ( suggestedby_borrowernumber ) %][% suggestedby_surname %], [% suggestedby_firstname %] [% suggestedby_branchcode %] ([% suggestedby_description %])[% END %] +
      [% manageddate %][% IF ( managedby_borrowernumber ) %][% managedby_surname %], [% managedby_firstname %] [% managedby_branchcode %] ([% managedby_description %])[% END %]
      [% accepteddate %][% IF ( acceptedby_borrowernumber ) %][% acceptedby_surname %], [% acceptedby_firstname %] [% acceptedby_branchcode %] ([% acceptedby_description %])[% END %]
    +
    +
    Acquisition information +
      +
    1. + [% branchname %] +
    2. +
    3. + [% budgetname %] +
    4. +
    5. + [% quantity %] +
    6. +
    7. + [% currency %] +
    8. +
    9. + [% price %] +
    10. +
    11. + [% total %] +
    12. +
    +
    + + <<Back to the list + +
    +
    +
    +[% END %] [% IF ( op_save ) %]
    [% ELSE %]
    [% END %]
    @@ -189,7 +310,7 @@ $(document).ready(function() { calcNewsuggTotal(); }); -
    [% IF ( suggestionid ) %] Cancel[% ELSE %] Cancel[% END %] +
    [% IF ( suggestionid ) %] Cancel[% ELSE %] Cancel[% END %]
    [% END %] @@ -245,9 +366,9 @@ $(document).ready(function() { calcNewsuggTotal(); }); - - [% suggestions_loo.title |html %][% IF ( suggestions_loo.author ) %], by [% suggestions_loo.author %][% END %] - + + [% suggestions_loo.title |html %][% IF ( suggestions_loo.author ) %], by [% suggestions_loo.author %][% END %] + [edit]
    [% IF ( suggestions_loo.copyrightdate ) %]© [% suggestions_loo.copyrightdate %] [% END %] [% IF ( suggestions_loo.volumedesc ) %]; Volume:[% suggestions_loo.volumedesc %] [% END %] @@ -314,7 +435,7 @@ $(document).ready(function() { calcNewsuggTotal(); });
    - [% UNLESS ( op_save ) %]
    + [% UNLESS ( op_save ) %] [% UNLESS ( op == 'show' ) %]
    1. - - - - - [% IF ( iteminformatio.ITEM_SUBFIELDS_ARE_NOT_REPEATABLE ) %] - + - [% END %] - -
    +
    + Item + [% IF ( NoACQframework ) %] +

    + No ACQ framework, using default. You should create a + framework with code ACQ, the items framework would be + used +

    [% END %] - - Add - -
    -
    - - - - - - - - - [% END %] - - [% END %] +
    + + [% END %][%# IF (AcqCreateItemReceiving) %] @@ -94,12 +132,15 @@
  • [% IF ( memberfirstname and membersurname ) %][% IF ( memberfirstname ) %][% memberfirstname %][% END %] [% membersurname %][% ELSE %]No name[% END %]
  • [% IF ( edit ) %] - + [% ELSE %] - + [% END %]
  • + [% IF (AcqCreateItemReceiving) %] + + [% ELSE %] [% IF ( quantityreceived ) %] [% IF ( edit ) %] @@ -120,6 +161,7 @@ [% END %] [% END %] + [% END %][%# IF (AcqCreateItemReceiving) %]
  • @@ -135,7 +177,8 @@
    - Cancel + + Cancel
    [% ELSE %]
    diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/acquisitions.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/acquisitions.pref index 70e660d..d67954e 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/acquisitions.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/acquisitions.pref @@ -9,6 +9,9 @@ Acquisitions: receiving: receiving an order. cataloguing: cataloging the record. - + - pref: UniqueItemFields + - (space-separated list of fields that should be unique for items, must be valid SQL fields of items table) + - - When closing or reopening a basket, - pref: BasketConfirmations default: 1 diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/services/itemrecorddisplay.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/services/itemrecorddisplay.tt new file mode 100644 index 0000000..696aca4 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/services/itemrecorddisplay.tt @@ -0,0 +1,25 @@ +
      + [% FOREACH iteminfo IN iteminformation %] +
    1. +
      + + [% iteminfo.marc_value %] + + + + + +
      +
    2. + [% END %] +
    + diff --git a/services/itemrecorddisplay.pl b/services/itemrecorddisplay.pl new file mode 100755 index 0000000..af22c35 --- /dev/null +++ b/services/itemrecorddisplay.pl @@ -0,0 +1,58 @@ +#!/usr/bin/perl + +# Copyright 2011 BibLibre SARL +# 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +=head1 NAME + +itemrecorddisplay.pl + +=head1 DESCRIPTION + +Return a HTML form for Item record modification or creation. +It uses PrepareItemrecordDisplay + +=cut + +use strict; +use warnings; + +use CGI; +use C4::Auth; +use C4::Output; +use C4::Biblio; + +my $input = new CGI; +my ($template, $loggedinuser, $cookie, $flags) = get_template_and_user( { + template_name => 'services/itemrecorddisplay.tmpl', + query => $input, + type => 'intranet', + authnotrequired => 1, +} ); + +my $biblionumber = $input->param('biblionumber') || ''; +my $itemnumber = $input->param('itemnumber') || ''; +my $frameworkcode = $input->param('frameworkcode') || ''; + +my $result = PrepareItemrecordDisplay($biblionumber, $itemnumber, undef, $frameworkcode); +unless($result) { + $result = PrepareItemrecordDisplay($biblionumber, $itemnumber, undef, ''); +} + +$template->param(%$result); + +output_html_with_http_headers $input, $cookie, $template->output; + -- 1.7.9 From jonathan.druart at biblibre.com Wed Feb 22 17:25:32 2012 From: jonathan.druart at biblibre.com (Jonathan Druart) Date: Wed, 22 Feb 2012 17:25:32 +0100 Subject: [Koha-patches] [PATCH 1/1] Bug 7298: Export late orders as csv Message-ID: <1329927932-23388-1-git-send-email-jonathan.druart@biblibre.com> --- C4/Acquisition.pm | 33 +++++++-- acqui/lateorders-excel.pl | 65 +++++++++++++++++ acqui/lateorders.pl | 2 +- .../prog/en/modules/acqui/lateorders.tt | 77 +++++++++++++------- 4 files changed, 141 insertions(+), 36 deletions(-) create mode 100755 acqui/lateorders-excel.pl diff --git a/C4/Acquisition.pm b/C4/Acquisition.pm index 0a96a02..7be1ba6 100644 --- a/C4/Acquisition.pm +++ b/C4/Acquisition.pm @@ -842,17 +842,34 @@ C<$order> are fields from the biblio, biblioitems, aqorders tables of the Koha d sub GetOrder { my ($ordernumber) = @_; my $dbh = C4::Context->dbh; - my $query = " - SELECT biblioitems.*, biblio.*, aqorders.* - FROM aqorders - LEFT JOIN biblio on biblio.biblionumber=aqorders.biblionumber - LEFT JOIN biblioitems on biblioitems.biblionumber=aqorders.biblionumber - WHERE aqorders.ordernumber=? - - "; + my $query = qq{SELECT biblio.*,biblioitems.*, + aqorders.*, + aqbudgets.*, + aqbasket.*, + aqorders.rrp AS unitpricesupplier, + aqorders.ecost AS unitpricelib, + aqorders.claims_count AS claims_count, + aqorders.claimed_date AS claimed_date, + aqbudgets.budget_name AS budget, + aqbooksellers.name AS supplier, + aqbooksellers.id AS supplierid, + biblioitems.publishercode AS publisher, + ADDDATE(aqbasket.closedate, INTERVAL aqbooksellers.deliverytime DAY) AS estimateddeliverydate, + DATE(aqbasket.closedate) AS orderdate, + aqorders.quantity - IFNULL(aqorders.quantityreceived,0) AS quantity, + (aqorders.quantity - IFNULL(aqorders.quantityreceived,0)) * aqorders.rrp AS subtotal, + DATEDIFF(CURDATE( ),closedate) AS latesince + FROM aqorders LEFT JOIN biblio ON biblio.biblionumber = aqorders.biblionumber + LEFT JOIN biblioitems ON biblioitems.biblionumber = biblio.biblionumber + LEFT JOIN aqbudgets ON aqorders.budget_id = aqbudgets.budget_id, + aqbasket LEFT JOIN borrowers ON aqbasket.authorisedby = borrowers.borrowernumber + LEFT JOIN aqbooksellers ON aqbasket.booksellerid = aqbooksellers.id + WHERE aqorders.basketno = aqbasket.basketno + AND ordernumber=?}; my $sth= $dbh->prepare($query); $sth->execute($ordernumber); my $data = $sth->fetchrow_hashref; + $data->{orderdate} = format_date( $data->{orderdate} ); $sth->finish; return $data; } diff --git a/acqui/lateorders-excel.pl b/acqui/lateorders-excel.pl new file mode 100755 index 0000000..253ec78 --- /dev/null +++ b/acqui/lateorders-excel.pl @@ -0,0 +1,65 @@ +#!/usr/bin/perl + +# 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; +use CGI; +use C4::Auth; +use C4::Serials; +use C4::Acquisition; +use C4::Output; +use C4::Context; + +use Text::CSV::Encoded; +use open qw/ :std :utf8 /; + +my $csv = Text::CSV::Encoded->new ({ + encoding => undef, + quote_char => '"', + escape_char => '"', + sep_char => ',', + binary => 1, + }); + +my $query = new CGI; +my @ordernumbers = $query->param('ordernumber'); + +print $query->header( + -type => 'text/csv', + -attachment => "lateorders.csv", +); + +print "LATE ORDERS\n\n"; +print "ORDER DATE,ESTIMATED DELIVERY DATE,VENDOR,INFORMATION,TOTAL COST,BASKET,CLAIMS COUNT,CLAIMED DATE\n"; + +for my $ordernumber ( @ordernumbers ) { + my $order = GetOrder $ordernumber; + $csv->combine( + "(" . $$order{supplierid} . ") " . $$order{orderdate} . " (" . $$order{latesince} . " days)", + $$order{estimateddeliverydate}, + $$order{supplier}, + $$order{title} . ( $$order{author} ? " Author: $$order{author}" : "" ) . ( $$order{publisher} ? " Published by: $$order{publisher}" : "" ), + $$order{unitpricesupplier} . "x" . $$order{quantity} . " = " . $$order{subtotal} . " (" . $$order{budget} . ")", + $$order{basketname} . " (" . $$order{basketno} . ")", + $$order{claims_count}, + $$order{claimed_date} + ); + my $string = $csv->string; + print $string, "\n"; +} + +print ",,Total Number Late, " . scalar @ordernumbers . "\n"; + diff --git a/acqui/lateorders.pl b/acqui/lateorders.pl index 86b1300..cf5a107 100755 --- a/acqui/lateorders.pl +++ b/acqui/lateorders.pl @@ -77,7 +77,7 @@ unless ($delay =~ /^\d{1,3}$/) { } if ($op and $op eq "send_alert"){ - my @ordernums = $input->param("claim_for");# FIXME: Fallback values? + my @ordernums = $input->param("ordernumber");# FIXME: Fallback values? my $err; eval { $err = SendAlerts( 'claimacquisition', \@ordernums, $input->param("letter_code") ); # FIXME: Fallback value? diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/lateorders.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/lateorders.tt index cdb8711..5ec0e09 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/lateorders.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/lateorders.tt @@ -5,16 +5,38 @@ @@ -59,6 +81,11 @@ $(document).ready(function() { [% END %] + [% IF Supplier %] + + [% ELSE %] + + [% END %] @@ -66,16 +93,14 @@ $(document).ready(function() { - [% IF Supplier %] - - [% ELSE %] - - [% END %] [% FOREACH lateorder IN lateorders %] [% UNLESS ( loop.odd ) %] [% ELSE %][% END %] + - - [% END %] - - - - - - - - - + + + + + + + + + +
    Check all
    Uncheck all
    Order Date Vendor InformationBasket Claims count Claimed dateCheck all
    Uncheck all
    + + ([% lateorder.supplierid %]) [% lateorder.orderdate %] ([% lateorder.latesince %] days) @@ -107,27 +132,25 @@ $(document).ready(function() { [% lateorder.claims_count %] [% lateorder.claimed_date %] - [% UNLESS lateorder.budget_lock %] - - [% END %] -
    Total [% total %]    - -
    Total [% total %]   
    - +
    +

    + [% UNLESS lateorder.budget_lock %] +

    + [% END %] + [% ELSE %]

    There are no late orders.

    [% END %]
    -- 1.7.7.3 From julian.maurice at biblibre.com Thu Feb 23 10:41:09 2012 From: julian.maurice at biblibre.com (julian.maurice at biblibre.com) Date: Thu, 23 Feb 2012 10:41:09 +0100 Subject: [Koha-patches] [SIGNED-OFF] [PATCH] Bug 7579 - Icons for authorized values/item types not showing in OPAC Message-ID: <1329990069-6133-1-git-send-email-julian.maurice@biblibre.com> From: Kyle M Hall The functions getitemtypeimagedir and getitemtypeimagesrc in Koha.pm were using the system preference 'template' when they should be using 'opacthemes' instead. Signed-off-by: Julian Maurice --- C4/Koha.pm | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/C4/Koha.pm b/C4/Koha.pm index 976b46a..43bfdf5 100644 --- a/C4/Koha.pm +++ b/C4/Koha.pm @@ -452,7 +452,7 @@ sub getitemtypeimagedir { if ($src eq 'intranet') { return C4::Context->config('intrahtdocs') . '/' .C4::Context->preference('template') . '/img/itemtypeimg'; } else { - return C4::Context->config('opachtdocs') . '/' . C4::Context->preference('template') . '/itemtypeimg'; + return C4::Context->config('opachtdocs') . '/' . C4::Context->preference('opacthemes') . '/itemtypeimg'; } } @@ -461,7 +461,7 @@ sub getitemtypeimagesrc { if ($src eq 'intranet') { return '/intranet-tmpl' . '/' . C4::Context->preference('template') . '/img/itemtypeimg'; } else { - return '/opac-tmpl' . '/' . C4::Context->preference('template') . '/itemtypeimg'; + return '/opac-tmpl' . '/' . C4::Context->preference('opacthemes') . '/itemtypeimg'; } } -- 1.7.9 From julian.maurice at biblibre.com Thu Feb 23 10:42:15 2012 From: julian.maurice at biblibre.com (julian.maurice at biblibre.com) Date: Thu, 23 Feb 2012 10:42:15 +0100 Subject: [Koha-patches] [PATCH] [SIGNED-OFF] Bug 7558: Serial issue note doubled up in full history Message-ID: <1329990135-6187-1-git-send-email-julian.maurice@biblibre.com> From: Katrin Fischer Removes the note behind the status, because there is a separate column. To test: - Add a subscription - Receive an issue, add a note for it - Search record in OPAC and check the full history tab for the note Signed-off-by: Julian Maurice --- .../prog/en/modules/opac-full-serial-issues.tt | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/koha-tmpl/opac-tmpl/prog/en/modules/opac-full-serial-issues.tt b/koha-tmpl/opac-tmpl/prog/en/modules/opac-full-serial-issues.tt index 0729ea6..2f956e8 100644 --- a/koha-tmpl/opac-tmpl/prog/en/modules/opac-full-serial-issues.tt +++ b/koha-tmpl/opac-tmpl/prog/en/modules/opac-full-serial-issues.tt @@ -206,7 +206,6 @@ function showlayer(numlayer){ [% IF ( serial.status4 ) %]Missing[% END %] [% IF ( serial.status5 ) %]Not Available[% END %] [% IF ( serial.status7 ) %]Claimed[% END %] - [% IF ( serial.notes ) %]([% serial.notes %])[% END %] [% serial.subscriptionid %] -- 1.7.9 From julian.maurice at biblibre.com Thu Feb 23 10:42:36 2012 From: julian.maurice at biblibre.com (julian.maurice at biblibre.com) Date: Thu, 23 Feb 2012 10:42:36 +0100 Subject: [Koha-patches] [PATCH] [SIGNED-OFF] Bug 7523: Improve checks for routing permissions Message-ID: <1329990156-6248-1-git-send-email-julian.maurice@biblibre.com> From: Katrin Fischer - system preference RoutingSerials and user permission routing should be taken into account - print routing list should be independent from routing permission To test, compare to master and check: 1) If system preference RoutingSerials is OFF, routing list functionality is not visible in the templates. 2) If system preference RoutingSerials is ON, but user doesn't have routing permission, routing list functionality is not visible in templates, with exception of 'print list' on the serial collection page. 3) If system preference RoutingSerials is ON and user has routing permissions, all routing links are visible (serial collection, serials navigation, result list of serial search) Additional changes: Changed labels on templates to match HTML4 rule from coding guidelines. http://wiki.koha-community.org/wiki/Coding_Guidelines#Upper_and_Lower_cases_in_strings Signed-off-by: Julian Maurice --- .../prog/en/includes/serials-menu.inc | 14 ++++---- .../prog/en/modules/serials/routing-preview.tt | 4 +- .../prog/en/modules/serials/serials-collection.tt | 30 +++++++++++-------- .../prog/en/modules/serials/serials-edit.tt | 10 +++--- .../prog/en/modules/serials/serials-home.tt | 28 +++++++++--------- serials/routing-preview.pl | 4 +- serials/serials-collection.pl | 1 + serials/subscription-detail.pl | 1 + 8 files changed, 49 insertions(+), 43 deletions(-) diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/serials-menu.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/serials-menu.inc index b54c842..0feafda 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/serials-menu.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/serials-menu.inc @@ -1,13 +1,13 @@ [% IF ( subscriptionid ) %] [% END %] @@ -16,6 +16,6 @@
  • Claims
  • [% END %] [% IF ( CAN_user_serials_check_expiration ) %] -
  • Check Expiration
  • +
  • Check expiration
  • [% END %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/serials/routing-preview.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/serials/routing-preview.tt index 2cc1936..b48e902 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/serials/routing-preview.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/serials/routing-preview.tt @@ -24,14 +24,14 @@ function print_slip(subscriptionid,issue){
    -

    Preview Routing List for [% title |html %]

    +

    Preview routing list for [% title |html %]

    1. Issue:[% issue %]
    2. -
    3. List Member: +
    4. List member:
    5. [% FOREACH memberloo IN memberloop %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/serials/serials-collection.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/serials/serials-collection.tt index 7b8efef..1db30c1 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/serials/serials-collection.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/serials/serials-collection.tt @@ -64,7 +64,7 @@ $(document).ready(function() { [% UNLESS ( popup ) %] [% INCLUDE 'serials-toolbar.inc' %] -

      Serial Collection information for [% bibliotitle %] +

      Serial collection information for [% bibliotitle %] [% IF location %] ([% location %] ) [% END %] [% IF ( callnumber ) %]callnumber: [% callnumber %][% END %]

      [% END %] @@ -72,18 +72,18 @@ $(document).ready(function() { [% IF ( subscriptions ) %]
      Name
      [% memberloo.surname %], [% memberloo.firstname %]
      [% IF ( subscriptions.size == 1 ) %] - + [% ELSE %] - + [% END %] - + - + [% IF ( routing && CAN_user_serials_routing ) %][% END %] [% FOREACH subscription IN subscriptions %] @@ -146,10 +146,14 @@ $(document).ready(function() { [% END %] - - + [% IF ( routing && CAN_user_serials_routing ) %] + + [% END %] [% IF ( subscription.abouttoexpire ) %] [% ELSE %] [% IF ( subscription.subscriptionexpired ) %] @@ -199,9 +203,7 @@ $(document).ready(function() { - - + [% IF ( routing ) %][% END %] [% IF ( CAN_user_serials_receive_serials ) %][% END %] [% FOREACH serial IN year.serials %] @@ -227,9 +229,11 @@ $(document).ready(function() { - + [% IF ( routing ) %] + + [% END %] [% IF ( CAN_user_serials_receive_serials ) %] - [% IF ( routing ) %] + [% IF ( routing && CAN_user_serials_routing ) %] [% END %] @@ -99,7 +99,7 @@ Serials updated : - + [% IF ( routing && CAN_user_serials_routing ) %][% END %] @@ -120,20 +120,20 @@ Serials updated : [% IF ( subscription.branchcode ) %][% subscription.branchcode %][% END %] [% IF ( subscription.callnumber ) %]([% subscription.callnumber %])[% END %] - [% IF ( routing ) %] + [% IF ( routing && CAN_user_serials_routing ) %] [% END %] -
      Subscription Summary Subscription summary Subscription Summaries Subscription summaries
      Subscription Num. Subscription num. Frequency Numbering pattern Library Call number NotesRoutingRoutingRenew
      [% subscription.branchcode %] [% subscription.callnumber %] [% subscription.notes %] [% IF ( subscription.subscriptionexpired ) %]
      Subscription Expired +
      [% subscription.notes %] [% IF ( subscription.subscriptionexpired ) %]
      Subscription expired [% END %]
      Edit Routing List + Edit routing list + Renew Renew Branch Routing - RoutingEdit
      [% serial.branchcode %] - Print list - + Print list + [% IF ( serial.cannotedit ) %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/serials/serials-edit.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/serials/serials-edit.tt index f82f791..083580b 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/serials/serials-edit.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/serials/serials-edit.tt @@ -431,12 +431,12 @@ $(document).ready(function() { [% INCLUDE 'serials-menu.inc' %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/serials/serials-home.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/serials/serials-home.tt index ec1faf3..8c50a17 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/serials/serials-home.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/serials/serials-home.tt @@ -84,9 +84,9 @@ Serials updated : Title Notes - Library (Callnumber) + Library (callnumber) Routing list 
      - [% IF ( subscription.cannotedit ) %] -   - [% ELSE %] - [% IF ( subscription.routingedit ) %] - Edit - [% ELSE %] - New - [% END %] - [% END %] + [% IF ( subscription.cannotedit ) %] +   + [% ELSE %] + [% IF ( subscription.routingedit ) %] + Edit + [% ELSE %] + New + [% END %] + [% END %] Issue History + Issue history [% IF ( subscription.cannotedit ) %] diff --git a/serials/routing-preview.pl b/serials/routing-preview.pl index 6746f53..6c8f184 100755 --- a/serials/routing-preview.pl +++ b/serials/routing-preview.pl @@ -99,7 +99,7 @@ if($ok){ query => $query, type => "intranet", authnotrequired => 0, - flagsrequired => {serials => 'routing'}, + flagsrequired => {serials => '*'}, debug => 1, }); $template->param("libraryname"=>$branchname); @@ -109,7 +109,7 @@ if($ok){ query => $query, type => "intranet", authnotrequired => 0, - flagsrequired => {serials => 'routing'}, + flagsrequired => {serials => '*'}, debug => 1, }); } diff --git a/serials/serials-collection.pl b/serials/serials-collection.pl index 4fe55f0..7453e86 100755 --- a/serials/serials-collection.pl +++ b/serials/serials-collection.pl @@ -158,6 +158,7 @@ $template->param( bibliotitle => $title, suggestion => C4::Context->preference("suggestion"), virtualshelves => C4::Context->preference("virtualshelves"), + routing => C4::Context->preference("RoutingSerials"), subscr=>$query->param('subscriptionid'), subscriptioncount => $subscriptioncount, location => $locationlib, diff --git a/serials/subscription-detail.pl b/serials/subscription-detail.pl index 0b6d35a..afe633e 100755 --- a/serials/subscription-detail.pl +++ b/serials/subscription-detail.pl @@ -124,6 +124,7 @@ $template->param( subscriptionid => $subscriptionid, serialslist => \@serialslist, hasRouting => $hasRouting, + routing => C4::Context->preference("RoutingSerials"), totalissues => $totalissues, hemisphere => $hemisphere, cannotedit =>(C4::Context->preference('IndependantBranches') && -- 1.7.9 From cnighswonger at foundations.edu Thu Feb 23 16:30:53 2012 From: cnighswonger at foundations.edu (Chris Nighswonger) Date: Thu, 23 Feb 2012 10:30:53 -0500 Subject: [Koha-patches] [PATCH] Bug 7585 - Correct MARC 008 Value Builder Char 06 Default Message-ID: <1330011053-30390-1-git-send-email-cnighswonger@foundations.edu> This patch changes the default value of the 06 char in 008 from 't' to 'b.' This change allows for a valid 008 field if no dates are entered in 07-14. To test: 1. Create a new MARC record (prior to patch application). 2. Click on the 008 field to auto-populate. 3. Note that the 06 char is 't'. 4. Apply patch. 5. Create a new MARC record. 6. Click on the 008 field to auto-populate. 7. Note that the 06 char is now 'b'. --- cataloguing/value_builder/marc21_field_008.pl | 5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-) diff --git a/cataloguing/value_builder/marc21_field_008.pl b/cataloguing/value_builder/marc21_field_008.pl index 5b8a7e5..bb7e7ee 100755 --- a/cataloguing/value_builder/marc21_field_008.pl +++ b/cataloguing/value_builder/marc21_field_008.pl @@ -58,7 +58,7 @@ function Focus$function_name(subfield_managed) { if ( document.getElementById(\"$field_number\").value ) { } else { - document.getElementById(\"$field_number\").value='$dateentered' + 't xxu||||| |||| 00| 0 eng d'; + document.getElementById(\"$field_number\").value='$dateentered' + 'b xxu||||| |||| 00| 0 eng d'; } return 1; } @@ -96,8 +96,7 @@ sub plugin { } ); - # $result = " t xxu 00 0 eng d" unless $result; - $result = "$dateentered" . "t xxu||||| |||| 00| 0 eng d" unless $result; + $result = "$dateentered" . "b xxu||||| |||| 00| 0 eng d" unless $result; my $errorXml = ''; # Check if the xml, xsd exists and is validated my $dir = C4::Context->config('intrahtdocs') . '/prog/' . $template->{lang} . '/modules/cataloguing/value_builder/'; -- 1.7.0.4 From gcollum at gmail.com Sat Feb 25 21:18:38 2012 From: gcollum at gmail.com (Garry Collum) Date: Sat, 25 Feb 2012 15:18:38 -0500 Subject: [Koha-patches] [PATCH] Bug 7517: Revised Patch. Patron category types not displaying in dropdown. Message-ID: <1330201118-1304-1-git-send-email-gcollum@gmail.com> The patron category drop-down box does not display the general category groups as it once did. This patch fixes the display of the optgroups. To test. Before applying the patch, go to a patron record. Edit the patron. Select the category drop-down in Library Management to see if the general categories appear. After the patch is applied the dropdown will show the categories. 'Child' - child categories, 'Adult' - adult categories, etc. Fixes XHTML errors. 1. Invalid end tag for cardnumber input. 2. Extra quote in textarea. 3. The label for debarredcomment did not have a corresponding id. There are two instances of this id field because of an 'IF' statement, this patch failed QA in the prior patch because only one of these ids was changed. --- .../prog/en/modules/members/memberentrygen.tt | 20 ++++++++++---------- 1 files changed, 10 insertions(+), 10 deletions(-) diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt index 7377ec6..ca158fd 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt @@ -176,7 +176,7 @@ [% IF step == 4 || step == 5 || step == 6 || step == 2 || step == 1 %] [%# Only put the cardnumber if we arent showing it in the form later %] [% IF cardnumber %] - + [% END %] [% END %] [% END %] @@ -992,12 +992,12 @@ [% FOREACH typeloo IN typeloop %] [% FOREACH categoryloo IN typeloo.categoryloop %] [% IF ( loop.first ) %] - [% IF ( categoryloo.typename_C ) %][% END %] - [% IF ( categoryloo.typename_A ) %][% END %] - [% IF ( categoryloo.typename_S ) %][% END %] - [% IF ( categoryloo.typename_I ) %][% END %] - [% IF ( categoryloo.typename_P ) %][% END %] - [% IF ( categoryloo.typename_X ) %][% END %] + [% IF ( typeloo.typename_C ) %][% END %] + [% IF ( typeloo.typename_A ) %][% END %] + [% IF ( typeloo.typename_S ) %][% END %] + [% IF ( typeloo.typename_I ) %][% END %] + [% IF ( typeloo.typename_P ) %][% END %] + [% IF ( typeloo.typename_X ) %][% END %] [% END %] [% IF ( categoryloo.categorycodeselected ) %] @@ -1307,9 +1307,9 @@
      [% IF opduplicate %] - + [% ELSE %] - + [% END %] Show Calendar