X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=blobdiff_plain;f=FS%2FFS%2Fcust_bill.pm;h=62ab87f0fae5f8ab33c53abb9e34fac224b4cb05;hp=a7eb9f64ab8269a3181ab037fe4f2e2cca6ef7fd;hb=0f7643c1af2d909e0c3172e5bec0c01855fca1b9;hpb=387c96b0d8f224f3ade27bed9348f37b432bbb8a diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index a7eb9f64a..62ab87f0f 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -1,7 +1,8 @@ package FS::cust_bill; use strict; -use vars qw( @ISA $DEBUG $me $conf $money_char $date_format $rdate_format ); +use vars qw( @ISA $DEBUG $me $conf + $money_char $date_format $rdate_format $date_format_long ); use vars qw( $invoice_lines @buf ); #yuck use Fcntl qw(:flock); #for spool_csv use List::Util qw(min max); @@ -45,9 +46,10 @@ $me = '[FS::cust_bill]'; #ask FS::UID to run this stuff for us later FS::UID->install_callback( sub { $conf = new FS::Conf; - $money_char = $conf->config('money_char') || '$'; - $date_format = $conf->config('date_format') || '%x'; - $rdate_format = $conf->config('date_format') || '%m/%d/%Y'; + $money_char = $conf->config('money_char') || '$'; + $date_format = $conf->config('date_format') || '%x'; #/YY + $rdate_format = $conf->config('date_format') || '%m/%d/%Y'; #/YYYY + $date_format_long = $conf->config('date_format_long') || '%b %o, %Y'; } ); =head1 NAME @@ -1239,8 +1241,14 @@ sub email { my @invoicing_list = grep { $_ !~ /^(POST|FAX)$/ } $self->cust_main->invoicing_list; - #better to notify this person than silence - @invoicing_list = ($invoice_from) unless @invoicing_list; + if ( ! @invoicing_list ) { #no recipients + if ( $conf->exists('cust_bill-no_recipients-error') ) { + die 'No recipients for customer #'. $self->custnum; + } else { + #default: better to notify this person than silence + @invoicing_list = ($invoice_from); + } + } my $subject = $self->email_subject($template); @@ -1950,7 +1958,8 @@ sub realtime_lec { } sub realtime_bop { - my( $self, $method ) = @_; + my( $self, $method ) = (shift,shift); + my %opt = @_; my $cust_main = $self->cust_main; my $balance = $cust_main->balance; @@ -1979,6 +1988,7 @@ sub realtime_bop { #this didn't do what we want, it just calls apply_payments_and_credits # 'apply' => 1, 'apply_to_invoice' => 1, + %opt, #what we want: #this changes application behavior: auto payments #triggered against a specific invoice are now applied @@ -2291,15 +2301,19 @@ sub print_generic { my $nbsp = $nbsps{$format}; my %escape_functions = ( 'latex' => \&_latex_escape, - 'html' => \&_html_escape, #\&encode_entities, + 'html' => \&_html_escape_nbsp,#\&encode_entities, 'template' => sub { shift }, ); my $escape_function = $escape_functions{$format}; + my $escape_function_nonbsp = ($format eq 'html') + ? \&_html_escape : $escape_function; - my %date_formats = ( 'latex' => '%b %o, %Y', - 'html' => '%b %o, %Y', + my %date_formats = ( 'latex' => $date_format_long, + 'html' => $date_format_long, 'template' => '%s', ); + $date_formats{'html'} =~ s/ / /g; + my $date_format = $date_formats{$format}; my %embolden_functions = ( 'latex' => sub { return '\textbf{'. shift(). '}' @@ -2376,7 +2390,7 @@ sub print_generic { #invoice info 'invnum' => $self->invnum, 'date' => time2str($date_format, $self->_date), - 'today' => time2str('%b %o, %Y', $today), + 'today' => time2str($date_format_long, $today), 'terms' => $self->terms, 'template' => $template, #params{'template'}, 'notice_name' => ($params{'notice_name'} || 'Invoice'),#escape_function? @@ -2598,7 +2612,7 @@ sub print_generic { my $extra_lines = (); if ( $multisection ) { ($extra_sections, $extra_lines) = - $self->_items_extra_usage_sections($escape_function, $format) + $self->_items_extra_usage_sections($escape_function_nonbsp, $format) if $conf->exists('usage_class_as_a_section', $cust_main->agentnum); push @$extra_sections, $adjust_section if $adjust_section->{sort_weight}; @@ -2607,13 +2621,13 @@ sub print_generic { push @sections, $self->_items_sections( $late_sections, # this could stand a refactor $summarypage, - $escape_function, + $escape_function_nonbsp, $extra_sections, $format, #bah ); if ($conf->exists('svc_phone_sections')) { my ($phone_sections, $phone_lines) = - $self->_items_svc_phone_sections($escape_function, $format); + $self->_items_svc_phone_sections($escape_function_nonbsp, $format); push @{$late_sections}, @$phone_sections; push @detail_items, @$phone_lines; } @@ -2658,6 +2672,16 @@ sub print_generic { $money_char. sprintf("%10.2f", $pr_total) ]; push @buf, ['','']; } + + if ( $conf->exists('svc_phone-did-summary') ) { + my ($didsummary,$minutes) = $self->_did_summary; + my $didsummary_desc = 'DID Activity Summary (Past 30 days)'; + push @detail_items, + { 'description' => $didsummary_desc, + 'ext_description' => [ $didsummary, $minutes ], + } + if !$multisection; + } foreach my $section (@sections, @$late_sections) { @@ -3080,7 +3104,6 @@ sub print_ps { my ($file, $lfile) = $self->print_latex(@_); my $ps = generate_ps($file); - unlink($file.'.tex'); unlink($lfile); $ps; @@ -3109,7 +3132,6 @@ sub print_pdf { my ($file, $lfile) = $self->print_latex(@_); my $pdf = generate_pdf($file); - unlink($file.'.tex'); unlink($lfile); $pdf; @@ -3165,10 +3187,14 @@ sub _latex_escape { $value; } - sub _html_escape { my $value = shift; encode_entities($value); + $value; +} + +sub _html_escape_nbsp { + my $value = _html_escape(shift); $value =~ s/ +/ /g; $value; } @@ -3789,6 +3815,72 @@ sub _items_extra_usage_sections { } +sub _did_summary { + my $self = shift; + my $end = $self->_date; + my $start = $end - 2592000; # 30 days + my $cust_main = $self->cust_main; + my @pkgs = $cust_main->all_pkgs; + my($num_activated,$num_deactivated,$num_portedin,$num_portedout,$minutes) + = (0,0,0,0,0); + my @seen = (); + foreach my $pkg ( @pkgs ) { + my @h_cust_svc = $pkg->h_cust_svc($end); + foreach my $h_cust_svc ( @h_cust_svc ) { + next if grep {$_ eq $h_cust_svc->svcnum} @seen; + next unless $h_cust_svc->part_svc->svcdb eq 'svc_phone'; + + my $inserted = $h_cust_svc->date_inserted; + my $deleted = $h_cust_svc->date_deleted; + my $phone_inserted = $h_cust_svc->h_svc_x($inserted); + my $phone_deleted; + $phone_deleted = $h_cust_svc->h_svc_x($deleted) if $deleted; + +# DID either activated or ported in; cannot be both for same DID simultaneously + if ($inserted >= $start && $inserted <= $end && $phone_inserted + && (!$phone_inserted->lnp_status + || $phone_inserted->lnp_status eq '' + || $phone_inserted->lnp_status eq 'native')) { + $num_activated++; + } + else { # this one not so clean, should probably move to (h_)svc_phone + my $phone_portedin = qsearchs( 'h_svc_phone', + { 'svcnum' => $h_cust_svc->svcnum, + 'lnp_status' => 'portedin' }, + FS::h_svc_phone->sql_h_searchs($end), + ); + $num_portedin++ if $phone_portedin; + } + +# DID either deactivated or ported out; cannot be both for same DID simultaneously + if($deleted >= $start && $deleted <= $end && $phone_deleted + && (!$phone_deleted->lnp_status + || $phone_deleted->lnp_status ne 'portingout')) { + $num_deactivated++; + } + elsif($deleted >= $start && $deleted <= $end && $phone_deleted + && $phone_deleted->lnp_status + && $phone_deleted->lnp_status eq 'portingout') { + $num_portedout++; + } + + # increment usage minutes + my @cdrs = $phone_inserted->get_cdrs('begin'=>$start,'end'=>$end); + foreach my $cdr ( @cdrs ) { + $minutes += $cdr->billsec/60; + } + + # don't look at this service again + push @seen, $h_cust_svc->svcnum; + } + } + + $minutes = sprintf("%d", $minutes); + ("Activated: $num_activated Ported-In: $num_portedin Deactivated: " + . "$num_deactivated Ported-Out: $num_portedout ", + "Total Minutes: $minutes"); +} + sub _items_svc_phone_sections { my $self = shift; my $escape = shift; @@ -4043,19 +4135,23 @@ sub _items_cust_bill_pkg { my $summary_page = $opt{summary_page} || ''; my $multilocation = $opt{multilocation} || ''; my $multisection = $opt{multisection} || ''; + my $discount_show_always = 0; my @b = (); my ($s, $r, $u) = ( undef, undef, undef ); foreach my $cust_bill_pkg ( @$cust_bill_pkg ) { + $discount_show_always = ($cust_bill_pkg->cust_bill_pkg_discount + && $conf->exists('discount-show-always')); + foreach ( $s, $r, ($opt{skip_usage} ? () : $u ) ) { if ( $_ && !$cust_bill_pkg->hidden ) { $_->{amount} = sprintf( "%.2f", $_->{amount} ), $_->{amount} =~ s/^\-0\.00$/0.00/; $_->{unit_amount} = sprintf( "%.2f", $_->{unit_amount} ), push @b, { %$_ } - unless $_->{amount} == 0; + unless ( $_->{amount} == 0 && !$discount_show_always ); $_ = undef; } } @@ -4094,15 +4190,20 @@ sub _items_cust_bill_pkg { unless ( $cust_pkg->part_pkg->hide_svc_detail || $cust_bill_pkg->hidden ) { + push @d, map &{$escape_function}($_), - $cust_pkg->h_labels_short($self->_date); + $cust_pkg->h_labels_short($self->_date, undef, 'I') + unless $cust_bill_pkg->pkgpart_override; #don't redisplay services + if ( $multilocation ) { my $loc = $cust_pkg->location_label; $loc = substr($loc, 0, 50). '...' if $format eq 'latex' && length($loc) > 50; push @d, &{$escape_function}($loc); } + } + push @d, $cust_bill_pkg->details(%details_opt) if $cust_bill_pkg->recur == 0; @@ -4124,7 +4225,8 @@ sub _items_cust_bill_pkg { } - if ( ( $cust_bill_pkg->recur != 0 || $cust_bill_pkg->setup == 0 ) && + if ( ( $cust_bill_pkg->recur != 0 || $cust_bill_pkg->setup == 0 || + ($discount_show_always && $cust_bill_pkg->recur == 0) ) && ( !$type || $type eq 'R' || $type eq 'U' ) ) { @@ -4145,23 +4247,27 @@ sub _items_cust_bill_pkg { my @dates = ( $self->_date ); my $prev = $cust_bill_pkg->previous_cust_bill_pkg; push @dates, $prev->sdate if $prev; + push @dates, undef if !$prev; unless ( $cust_pkg->part_pkg->hide_svc_detail || $cust_bill_pkg->itemdesc || $cust_bill_pkg->hidden || $is_summary && $type && $type eq 'U' ) { + push @d, map &{$escape_function}($_), - $cust_pkg->h_labels_short(@dates) + $cust_pkg->h_labels_short(@dates, 'I') #$cust_bill_pkg->edate, #$cust_bill_pkg->sdate) - ; + unless $cust_bill_pkg->pkgpart_override; #don't redisplay services + if ( $multilocation ) { my $loc = $cust_pkg->location_label; $loc = substr($loc, 0, 50). '...' if $format eq 'latex' && length($loc) > 50; push @d, &{$escape_function}($loc); } + } push @d, $cust_bill_pkg->details(%details_opt) @@ -4245,7 +4351,7 @@ sub _items_cust_bill_pkg { $_->{amount} =~ s/^\-0\.00$/0.00/; $_->{unit_amount} = sprintf( "%.2f", $_->{unit_amount} ), push @b, { %$_ } - unless $_->{amount} == 0; + unless ( $_->{amount} == 0 && !$discount_show_always ); } }