From 9f97c81b19a3184ea68df32aaea43808b22e10f0 Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Thu, 22 Mar 2012 22:08:54 -0700 Subject: [PATCH] customer signup report, #17050 --- FS/FS/Report/Table.pm | 18 +++++++ FS/FS/cust_main/Search.pm | 9 ++++ httemplate/elements/menu.html | 1 + httemplate/graph/cust_signup.html | 83 ++++++++++++++++++++++++++++++++ httemplate/graph/elements/monthly.html | 3 +- httemplate/graph/elements/report.html | 10 ++-- httemplate/graph/report_cust_signup.html | 37 ++++++++++++++ httemplate/search/cust_main.html | 1 + 8 files changed, 157 insertions(+), 5 deletions(-) create mode 100644 httemplate/graph/cust_signup.html create mode 100644 httemplate/graph/report_cust_signup.html diff --git a/FS/FS/Report/Table.pm b/FS/FS/Report/Table.pm index e8971ec7a..3942543b5 100644 --- a/FS/FS/Report/Table.pm +++ b/FS/FS/Report/Table.pm @@ -32,6 +32,24 @@ options in %opt. =over 4 +=item signups: The number of customers signed up. + +=cut + +sub signups { + my( $self, $speriod, $eperiod, $agentnum, %opt ) = @_; + my @where = ( + $self->in_time_period_and_agent($speriod, $eperiod, $agentnum, 'signupdate') + ); + if ( $opt{'refnum'} ) { + push @where, "refnum = ".$opt{'refnum'}; + } + + $self->scalar_sql( + "SELECT COUNT(*) FROM cust_main WHERE ".join(' AND ', @where) + ); +} + =item invoiced: The total amount charged on all invoices. =cut diff --git a/FS/FS/cust_main/Search.pm b/FS/FS/cust_main/Search.pm index c5b5ff6d0..62464e4aa 100644 --- a/FS/FS/cust_main/Search.pm +++ b/FS/FS/cust_main/Search.pm @@ -447,6 +447,8 @@ HASHREF. Valid parameters are =item address +=item refnum + =item cancelled_pkgs bool @@ -553,6 +555,13 @@ sub search { ')'; } + ### + # refnum + ### + if ( $params->{'refnum'} =~ /^(\d+)$/ ) { + push @where, "refnum = $1"; + } + ## # parse cancelled package checkbox ## diff --git a/httemplate/elements/menu.html b/httemplate/elements/menu.html index b3a555a9f..c65e990ae 100644 --- a/httemplate/elements/menu.html +++ b/httemplate/elements/menu.html @@ -108,6 +108,7 @@ tie my %report_customers, 'Tie::IxHash'; $report_customers{'List customers'} = [ \%report_customers_lists, 'List customers' ] if $curuser->access_right('List customers'); $report_customers{'Zip code distribution'} = [ $fsurl. 'search/report_cust_main-zip.html', 'Zip codes by number of customers' ]; +$report_customers{'Customer signup report'} = [ $fsurl. 'graph/report_cust_signup.html', 'New customer signups by date' ], $report_customers{'Advanced customer reports'} = [ $fsurl. 'search/report_cust_main.html', 'by status, signup date, agent, etc.' ] if $curuser->access_right('List customers') && $curuser->access_right('List packages'); diff --git a/httemplate/graph/cust_signup.html b/httemplate/graph/cust_signup.html new file mode 100644 index 000000000..dd9100f1e --- /dev/null +++ b/httemplate/graph/cust_signup.html @@ -0,0 +1,83 @@ +<& elements/monthly.html, + 'title' => $title, + 'items' => \@items, + 'labels' => \@labels, + 'graph_labels' => \@labels, + 'params' => \@params, + 'colors' => \@colors, + 'links' => \@links, + 'agentnum' => $agentnum, + 'sprintf' => '%u', + 'disable_money' => 1, + 'bottom_total' => (scalar @items > 1 ? 1 : 0), + 'bottom_link' => $bottom_link, + 'link_fromparam' => 'signupdate_begin', + 'link_toparam' => 'signupdate_end', + 'chart_options' => { precision => 0 }, +&> +<%init> + +#XXX use a different ACL for package churn? +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Financial reports'); + +#false laziness w/money_time.cgi, cust_bill_pkg.cgi +my $title = 'Customer Signup', + +#XXX or virtual +my( $agentnum, $agent ) = ('', ''); +if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) { + $agentnum = $1; + $agent = qsearchs('agent', { 'agentnum' => $agentnum } ); + die "agentnum $agentnum not found!" unless $agent; +} + +my $agentname = $agent ? $agent->agent.' ' : ''; +$title = "$agentname $title" if $agentname; + +my $link = $p.'search/cust_main.html?'; +$link .= "agentnum=$agentnum;" if $agentnum; + +my $bottom_link = $link; + +my @referral; +my $all_referral = 0; +if ( $cgi->param('refnum') eq 'all' ) { + @referral = (''); + $all_referral = 1; +} +elsif ( $cgi->param('refnum') =~ /^(\d*)$/ ) { + if ( $1 ) { + @referral = ( qsearchs('part_referral', { 'refnum' => $1 } ) ); + die "refnum $1 not found!" unless @referral; + $title .= ' - '.$referral[0]->referral; + $bottom_link .= ";refnum=$1"; + } + else { #refnum = '' + @referral = qsearch('part_referral', {}); + $title .= ' by Advertising Source'; + } +} + +my (@items, @labels, @colors, @params, @links); + +my $hue = 0; +my $hue_increment = 125; +my @signup_colors; + +foreach my $referral (@referral) { + push @items, 'signups'; + push @labels, ( $all_referral ? 'Signups' : $referral->referral ); + push @params, ( $all_referral ? [] : [ 'refnum' => $referral->refnum ] ); + push @links, $link . ($all_referral ? '' : "refnum=".$referral->refnum.';'); + if ( !@signup_colors ) { + @signup_colors = Color::Scheme->new + ->from_hue($hue) + ->scheme('analogic') + ->colors; + $hue += $hue_increment; + } + push @colors, shift @signup_colors; +} + + diff --git a/httemplate/graph/elements/monthly.html b/httemplate/graph/elements/monthly.html index 2fd605d5e..072798c2a 100644 --- a/httemplate/graph/elements/monthly.html +++ b/httemplate/graph/elements/monthly.html @@ -60,7 +60,8 @@ Example: graph_type bottom_total sprintf - disable_money)), + disable_money + chart_options)), ) %> <%init> diff --git a/httemplate/graph/elements/report.html b/httemplate/graph/elements/report.html index 382c41f6c..3600f2c66 100644 --- a/httemplate/graph/elements/report.html +++ b/httemplate/graph/elements/report.html @@ -142,7 +142,7 @@ any delimiter and linked from the elements in @data. % # after that we have to start skipping labels. also remove the dots, since % # they're just a blob at that point. % my $num_labels = scalar(@{ $opt{axis_labels} }); -% my %chart_opt; +% my %chart_opt = %{ $opt{chart_options} || {} }; % if ( $num_labels > 28 ) { % $chart_opt{x_ticks} = 'vertical'; % if ( $num_labels > 60 ) { @@ -212,7 +212,6 @@ any delimiter and linked from the elements in @data. % } % # i for item, e for entry - % my $i = 1; % foreach my $row ( @items ) { % #make a style @@ -225,11 +224,13 @@ any delimiter and linked from the elements in @data. % my $label = shift @row_labels; % $cell[$i] = [ $label ]; % -% my $data_row = shift @data; +% my $data_row = $data[$i-1]; +%# my $data_row = shift @data; % if ( ! $opt{'nototal'} ) { % push @$data_row, sum(@$data_row); % } -% foreach my $entry ( @$data_row ) { +% foreach ( @$data_row ) { +% my $entry = $_; % $entry = $money_char . sprintf($sprintf, $entry); % $entry = $link_prefix . shift(@$links) . "\">$entry" if $link_prefix; % push @{$cell[$i]}, $entry; @@ -242,6 +243,7 @@ any delimiter and linked from the elements in @data. % push @styles, ".i$i { text-align: right; background-color: #f5f6be; }"; % my $links = $opt{'bottom_link'} || []; % my $link_prefix = shift @$links; +% $link_prefix = ' + + + +<% include('/elements/tr-select-from_to.html' ) %> + +<% include('/elements/tr-select-agent.html', + 'curr_value' => scalar($cgi->param('agentnum')), + 'label' => 'For agent: ', + 'disable_empty' => 0, + ) +%> + +<% include('/elements/tr-select-part_referral.html', + 'curr_value' => scalar($cgi->param('refnum')), + 'label' => 'Advertising source: ', + 'disable_empty' => 0, + 'pre_options' => [ 'all' => 'all (aggregate)' ], + 'empty_label' => 'all (breakdown)', + ) +%> + +
+ +
+ + +<% include('/elements/footer.html') %> +<%init> + +#XXX use a different ACL for package churn? +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Financial reports'); + + diff --git a/httemplate/search/cust_main.html b/httemplate/search/cust_main.html index 693996ed5..498024ba0 100755 --- a/httemplate/search/cust_main.html +++ b/httemplate/search/cust_main.html @@ -47,6 +47,7 @@ my @scalars = qw ( no_censustract with_geocode custbatch usernum cancelled_pkgs cust_fields flattened_pkgs + refnum ); for my $param ( @scalars ) { -- 2.11.0