X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=C4%2FLetters.pm;h=712514896e1024650c0bd800716e6a2a3c228953;hb=54616c37e25b969907f9da2cf021e7e23ced836c;hp=a585ff88d542eaf6858cdf8b2cf70af9d4242bb1;hpb=5d7b5533f1565a55ff269fd82690a71a697901f1;p=koha.git diff --git a/C4/Letters.pm b/C4/Letters.pm index a585ff88d5..712514896e 100644 --- a/C4/Letters.pm +++ b/C4/Letters.pm @@ -29,9 +29,9 @@ use C4::Branch; use C4::Log; use C4::SMS; use C4::Debug; +use Koha::DateUtils; use Date::Calc qw( Add_Delta_Days ); use Encode; -use Unicode::Normalize; use Carp; use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); @@ -117,40 +117,18 @@ sub GetLetters { return \%letters; } -=head2 GetLetter( %params ) - - retrieves the letter template - - %params hash: - module => letter module, mandatory - letter_code => letter code, mandatory - branchcode => for letter selection, if missing default system letter taken - Return value: - letter fields hashref (title & content useful) - -=cut - -sub GetLetter { - 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; - - return $letter; -} - -my %letter; +# FIXME: using our here means that a Plack server will need to be +# restarted fairly regularly when working with this routine. +# A better option would be to use Koha::Cache and use a cache +# that actually works in a persistent environment, but as a +# short-term fix, our will work. +our %letter; sub getletter { my ( $module, $code, $branchcode ) = @_; $branchcode ||= ''; - if ( C4::Context->preference('IndependantBranches') + if ( C4::Context->preference('IndependentBranches') and $branchcode and C4::Context->userenv ) { @@ -310,6 +288,7 @@ sub SendAlerts { # warn "sending issues..."; my $userenv = C4::Context->userenv; + my $branchdetails = GetBranchDetail($_->{'branchcode'}); my $letter = GetPreparedLetter ( module => 'serial', letter_code => $letter_code, @@ -326,7 +305,7 @@ sub SendAlerts { # ... then send mail my %mail = ( To => $email, - From => $email, + From => $branchdetails->{'branchemail'} || C4::Context->preference("KohaAdminEmailAddress"), Subject => Encode::encode( "utf8", "" . $letter->{title} ), Message => Encode::encode( "utf8", "" . $letter->{content} ), 'Content-Type' => 'text/plain; charset="utf8"', @@ -345,7 +324,7 @@ sub SendAlerts { FROM aqorders LEFT JOIN aqbasket ON aqbasket.basketno=aqorders.basketno LEFT JOIN biblio ON aqorders.biblionumber=biblio.biblionumber - LEFT JOIN biblioitems ON aqorders.biblioitemnumber=biblioitems.biblioitemnumber + LEFT JOIN biblioitems ON aqorders.biblionumber=biblioitems.biblionumber LEFT JOIN aqbooksellers ON aqbasket.booksellerid=aqbooksellers.id WHERE aqorders.ordernumber IN ( } @@ -440,8 +419,6 @@ sub SendAlerts { =head2 GetPreparedLetter( %params ) - retrieves letter template and performs substituion processing - %params hash: module => letter module, mandatory letter_code => letter code, mandatory @@ -469,65 +446,14 @@ sub GetPreparedLetter { my $module = $params{module} or croak "No module"; my $letter_code = $params{letter_code} or croak "No letter_code"; my $branchcode = $params{branchcode} || ''; - my $tables = $params{tables}; - my $substitute = $params{substitute}; - my $repeat = $params{repeat}; my $letter = getletter( $module, $letter_code, $branchcode ) or warn( "No $module $letter_code letter"), return; - my $prepared_letter = GetProcessedLetter( - module => $module, - letter_code => $letter_code, - letter => $letter, - branchcode => $branchcode, - tables => $tables, - substitute => $substitute, - repeat => $repeat - ); - - return $prepared_letter; -} - -=head2 GetProcessedLetter( %params ) - - given a letter, with possible pre-processing do standard processing - allows one to perform letter template processing beforehand - - %params hash: - module => letter module, mandatory - letter_code => letter code, mandatory - letter => letter, 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 - -sub GetProcessedLetter { - my %params = @_; - - my $module = $params{module} or croak "No module"; - my $letter_code = $params{letter_code} or croak "No letter_code"; - my $letter = $params{letter} or croak "No letter"; - my $branchcode = $params{branchcode} || ''; 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; @@ -625,21 +551,24 @@ sub _substitute_tables { $sth->execute( $ref ? @$param : $param ); $values = $sth->fetchrow_hashref; + $sth->finish(); } _parseletter ( $letter, $table, $values ); } } -my %handles = (); sub _parseletter_sth { my $table = shift; + my $sth; unless ($table) { carp "ERROR: _parseletter_sth() called without argument (table)"; return; } - # check cache first - (defined $handles{$table}) and return $handles{$table}; + # NOTE: we used to check whether we had a statement handle cached in + # a %handles module-level variable. This was a dumb move and + # broke things for the rest of us. prepare_cached is a better + # way to cache statement handles anyway. my $query = ($table eq 'biblio' ) ? "SELECT * FROM $table WHERE biblionumber = ?" : ($table eq 'biblioitems' ) ? "SELECT * FROM $table WHERE biblionumber = ?" : @@ -659,11 +588,11 @@ sub _parseletter_sth { warn "ERROR: No _parseletter_sth query for table '$table'"; return; # nothing to get } - unless ($handles{$table} = C4::Context->dbh->prepare($query)) { + unless ($sth = C4::Context->dbh->prepare_cached($query)) { warn "ERROR: Failed to prepare query: '$query'"; return; } - return $handles{$table}; # now cache is populated for that $table + return $sth; # now cache is populated for that $table } =head2 _parseletter($letter, $table, $values) @@ -677,40 +606,33 @@ sub _parseletter_sth { =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'}; - $values->{'expirationdate'} = C4::Dates->new( - sprintf( - '%04d-%02d-%02d', - Add_Delta_Days( @waitingdate, C4::Context->preference( 'ReservesMaxPickUpDelay' ) ) - ), - 'iso' - )->output(); + my $dt = dt_from_string(); + $dt->add( days => C4::Context->preference('ReservesMaxPickUpDelay') || 0); + $values->{'expirationdate'} = output_pref({ dt => $dt, dateonly => 1 }); + + $values->{'waitingdate'} = output_pref({ dt => dt_from_string( $values->{'waitingdate'} ), dateonly => 1 }); + } if ($letter->{content} && $letter->{content} =~ /<>/) { - my @da = localtime(); - my $todaysdate = "$da[2]:$da[1] " . C4::Dates->today(); + my $todaysdate = output_pref( DateTime->now() ); $letter->{content} =~ s/<>/$todaysdate/go; } - # and get all fields from the table -# 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; + $val =~ s/\p{P}$// if $val && $table=~/biblio/; + #BZ 9886: Assuming that we want to eliminate ISBD punctuation here + #Therefore adding the test on biblio. This includes biblioitems, + #but excludes items. Removed unneeded global and lookahead. + my $replacedby = defined ($val) ? $val : ''; ($letter->{title} ) and do { $letter->{title} =~ s/$replacetablefield/$replacedby/g; @@ -770,12 +692,6 @@ sub EnqueueLetter { return; } - # It was found that the some utf8 codes, cause the text to be truncated from that point onward when stored, - # so we normalize utf8 with NFC so that mysql will store 'all' of the content in its TEXT column type - # Note: It is also done in _add_attachments accordingly. - $params->{'letter'}->{'title'} = NFC($params->{'letter'}->{'title'}); # subject - $params->{'letter'}->{'content'} = NFC($params->{'letter'}->{'content'}); - # If we have any attachments we should encode then into the body. if ( $params->{'attachments'} ) { $params->{'letter'} = _add_attachments( @@ -946,17 +862,11 @@ sub _add_attachments { $message->attach( Type => $letter->{'content-type'} || 'TEXT', Data => $letter->{'is_html'} - ? _wrap_html($letter->{'content'}, NFC($letter->{'title'})) - : NFC($letter->{'content'}), + ? _wrap_html($letter->{'content'}, $letter->{'title'}) + : $letter->{'content'}, ); foreach my $attachment ( @$attachments ) { - - if ($attachment->{'content'} =~ m/text/o) { # NFC normailze any "text" related content-type attachments - $attachment->{'content'} = NFC($attachment->{'content'}); - } - $attachment->{'filename'} = NFC($attachment->{'filename'}); - $message->attach( Type => $attachment->{'type'}, Data => $attachment->{'content'}, @@ -1010,22 +920,16 @@ sub _send_message_by_email { my $message = shift or return; my ($username, $password, $method) = @_; - my $to_address = $message->{to_address}; + my $member = C4::Members::GetMember( 'borrowernumber' => $message->{'borrowernumber'} ); + my $to_address = $message->{'to_address'}; unless ($to_address) { - my $member = C4::Members::GetMember( 'borrowernumber' => $message->{'borrowernumber'} ); unless ($member) { warn "FAIL: No 'to_address' and INVALID borrowernumber ($message->{borrowernumber})"; _set_message_status( { message_id => $message->{'message_id'}, status => 'failed' } ); return; } - my $which_address = C4::Context->preference('AutoEmailPrimaryAddress'); - # If the system preference is set to 'first valid' (value == OFF), look up email address - if ($which_address eq 'OFF') { - $to_address = GetFirstValidEmailAddress( $message->{'borrowernumber'} ); - } else { - $to_address = $member->{$which_address}; - } + $to_address = C4::Members::GetNoticeEmailAddress( $message->{'borrowernumber'} ); unless ($to_address) { # warn "FAIL: No 'to_address' and no email for " . ($member->{surname} ||'') . ", borrowernumber ($message->{borrowernumber})"; # warning too verbose for this more common case? @@ -1041,9 +945,12 @@ sub _send_message_by_email { 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 $branch_email = ( $member ) ? GetBranchDetail( $member->{'branchcode'} )->{'branchemail'} : undef; + my %sendmail_params = ( To => $to_address, - From => $message->{'from_address'} || C4::Context->preference('KohaAdminEmailAddress'), + From => $message->{'from_address'} || $branch_email || C4::Context->preference('KohaAdminEmailAddress'), Subject => $subject, charset => 'utf8', Message => $is_html ? _wrap_html($content, $subject) : $content,