X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=blobdiff_plain;f=FS%2FFS%2FMisc.pm;h=9a4318086fcfcf9aa22e0fc5f2751905e34ed881;hp=6f6f2e2e5f3401efba60f2c579de90be8b4cf66a;hb=389b6f1116c3309c2ee57a6c295ed1a793503095;hpb=94db42b47263cf72ce248da59898f82a1364b0fa diff --git a/FS/FS/Misc.pm b/FS/FS/Misc.pm index 6f6f2e2e5..9a4318086 100644 --- a/FS/FS/Misc.pm +++ b/FS/FS/Misc.pm @@ -22,6 +22,8 @@ use Encode; generate_ps generate_pdf do_print csv_from_fixed ocr_image + bytes_substr + money_pretty ); $DEBUG = 0; @@ -108,7 +110,7 @@ use Date::Format; use MIME::Entity; use Email::Sender::Simple qw(sendmail); use Email::Sender::Transport::SMTP; -use Email::Sender::Transport::SMTP::TLS; +use Email::Sender::Transport::SMTP::TLS 0.11; use FS::UID; FS::UID->install_callback( sub { @@ -154,6 +156,7 @@ sub send_email { unshift @mimeparts, { 'Type' => ( $options{'content-type'} || 'text/plain' ), + 'Charset' => 'UTF-8', 'Data' => $options{'body'}, 'Encoding' => ( $options{'content-type'} ? '-SUGGEST' : '7bit' ), 'Disposition' => 'inline', @@ -165,14 +168,22 @@ sub send_email { 'Type' => ( $options{'content-type'} || 'text/plain' ), 'Data' => $options{'body'}, 'Encoding' => ( $options{'content-type'} ? '-SUGGEST' : '7bit' ), + 'Charset' => 'UTF-8', ); } } + my $from = $options{from}; + $from =~ s/^\s*//; $from =~ s/\s*$//; + if ( $from =~ /^(.*)\s*<(.*@.*)>$/ ) { + # a common idiom + $from = $2; + } + my $domain; - if ( $options{'from'} =~ /\@([\w\.\-]+)/ ) { + if ( $from =~ /\@([\w\.\-]+)/ ) { $domain = $1; } else { warn 'no domain found in invoice from address '. $options{'from'}. @@ -247,7 +258,7 @@ sub send_email { push @to, $options{bcc} if defined($options{bcc}); local $@; # just in case eval { sendmail($message, { transport => $transport, - from => $options{from}, + from => $from, to => \@to }) }; my $error = ''; @@ -260,7 +271,7 @@ sub send_email { } # Logging - if ( $conf->exists('log_sent_mail') and $options{'custnum'} ) { + if ( $conf->exists('log_sent_mail') ) { my $cust_msg = FS::cust_msg->new({ 'env_from' => $options{'from'}, 'env_to' => join(', ', @to), @@ -271,9 +282,12 @@ sub send_email { 'custnum' => $options{'custnum'}, 'msgnum' => $options{'msgnum'}, 'status' => ($error ? 'failed' : 'sent'), + 'msgtype' => $options{'msgtype'}, }); - $cust_msg->insert; # ignore errors + my $log_error = $cust_msg->insert; + warn "Error logging message: $log_error\n" if $log_error; # at least warn } + $error; } @@ -329,7 +343,7 @@ sub generate_email { my $me = '[FS::Misc::generate_email]'; - my @fields = qw(from to bcc subject custnum msgnum); + my @fields = qw(from to bcc subject custnum msgnum msgtype); my %return; @return{@fields} = @args{@fields}; @@ -354,6 +368,7 @@ sub generate_email { $alternative->attach( 'Type' => 'text/plain', 'Encoding' => 'quoted-printable', + 'Charset' => 'UTF-8', #'Encoding' => '7bit', 'Data' => $data, 'Disposition' => 'inline', @@ -375,7 +390,7 @@ sub generate_email { ' '. encode_entities($return{'subject'}), ' ', ' ', - ' ', + ' ', @html_data, ' ', '', @@ -399,20 +414,6 @@ sub generate_email { } -=item process_send_email OPTION => VALUE ... - -Takes arguments as per generate_email() and sends the message. This -will die on any error and can be used in the job queue. - -=cut - -sub process_send_email { - my %message = @_; - my $error = send_email(generate_email(%message)); - die "$error\n" if $error; - ''; -} - =item send_fax OPTION => VALUE ... Options: @@ -509,6 +510,9 @@ use Locale::SubCountry; sub states_hash { my($country) = @_; + #a hash? not expecting an explosion of business from unrecognized countries.. + return states_hash_nosubcountry($country) if $country eq 'XC'; + my @states = # sort map { s/[\n\r]//g; $_; } @@ -522,7 +526,7 @@ sub states_hash { #it could throw a fatal "Invalid country code" error (for example "AX") my $subcountry = eval { new Locale::SubCountry($country) } - or return ( '', '(n/a)' ); + or return (); # ( '', '(n/a)' ); #"i see your schwartz is as big as mine!" map { ( $_->[0] => $_->[1] ) } @@ -531,6 +535,27 @@ sub states_hash { @states; } +sub states_hash_nosubcountry { + my($country) = @_; + + my @states = +# sort + map { s/[\n\r]//g; $_; } + map { $_->state; } + qsearch({ + 'select' => 'state', + 'table' => 'cust_main_county', + 'hashref' => { 'country' => $country }, + 'extra_sql' => 'GROUP BY state', + }); + + #"i see your schwartz is as big as mine!" + map { ( $_->[0] => $_->[1] ) } + sort { $a->[1] cmp $b->[1] } + map { [ $_ => $_ ] } + @states; +} + =item counties STATE COUNTRY Returns a list of counties for this state and country. @@ -692,13 +717,16 @@ sub generate_ps { _pslatex($file); - system('dvips', '-q', '-t', 'letter', "$file.dvi", '-o', "$file.ps" ) == 0 + my $papersize = $conf->config('papersize') || 'letter'; + + system('dvips', '-q', '-t', $papersize, "$file.dvi", '-o', "$file.ps" ) == 0 or die "dvips failed"; open(POSTSCRIPT, "<$file.ps") or die "can't open $file.ps: $! (error in LaTeX template?)\n"; - unlink("$file.dvi", "$file.log", "$file.aux", "$file.ps", "$file.tex"); + unlink("$file.dvi", "$file.log", "$file.aux", "$file.ps", "$file.tex") + unless $FS::CurrentUser::CurrentUser->option('save_tmp_typesetting'); my $ps = ''; @@ -746,8 +774,10 @@ sub generate_pdf { my $sfile = shell_quote $file; #system('dvipdf', "$file.dvi", "$file.pdf" ); + my $papersize = $conf->config('papersize') || 'letter'; + system( - "dvips -q -t letter -f $sfile.dvi ". + "dvips -q -f $sfile.dvi -t $papersize ". "| gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=$sfile.pdf ". " -c save pop -" ) == 0 @@ -756,7 +786,8 @@ sub generate_pdf { open(PDF, "<$file.pdf") or die "can't open $file.pdf: $! (error in LaTeX template?)\n"; - unlink("$file.dvi", "$file.log", "$file.aux", "$file.pdf", "$file.tex"); + unlink("$file.dvi", "$file.log", "$file.aux", "$file.pdf", "$file.tex") + unless $FS::CurrentUser::CurrentUser->option('save_tmp_typesetting'); my $pdf = ''; while () { @@ -795,20 +826,36 @@ sub _pslatex { } return if -e "$file.dvi" && -s "$file.dvi"; - die "pslatex $file.tex failed; see $file.log for details?\n"; + die "pslatex $file.tex failed, see $file.log for details?\n"; } -=item print ARRAYREF +=item do_print ARRAYREF [, OPTION => VALUE ... ] Sends the lines in ARRAYREF to the printer. +Options available are: + +=over 4 + +=item agentnum + +Uses this agent's 'lpr' configuration setting override instead of the global +value. + +=item lpr + +Uses this command instead of the configured lpr command (overrides both the +global value and agentnum). + =cut sub do_print { - my $data = shift; + my( $data, %opt ) = @_; - my $lpr = $conf->config('lpr'); + my $lpr = ( exists($opt{'lpr'}) && $opt{'lpr'} ) + ? $opt{'lpr'} + : $conf->config('lpr', $opt{'agentnum'} ); my $outerr = ''; run3 $lpr, $data, \$outerr, \$outerr; @@ -913,6 +960,42 @@ sub ocr_image { @lines; } +=item bytes_substr STRING, OFFSET[, LENGTH[, REPLACEMENT] ] + +A replacement for "substr" that counts raw bytes rather than logical +characters. Unlike "bytes::substr", will suppress fragmented UTF-8 characters +rather than output them. Unlike real "substr", is not an lvalue. + +=cut + +sub bytes_substr { + my ($string, $offset, $length, $repl) = @_; + my $bytes = substr( + Encode::encode('utf8', $string), + $offset, + $length, + Encode::encode('utf8', $repl) + ); + my $chk = $DEBUG ? Encode::FB_WARN : Encode::FB_QUIET; + return Encode::decode('utf8', $bytes, $chk); +} + +=item money_pretty + +Accepts a postive or negative numerical value. +Returns amount formatted for display, +including money character. + +=cut + +sub money_pretty { + my $amount = shift; + my $money_char = $conf->{'money_char'} || '$'; + $amount = sprintf("%0.2f",$amount); + $amount =~ s/^(-?)/$1$money_char/; + return $amount; +} + =back =head1 BUGS