summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Kohler <ivan@freeside.biz>2012-03-23 11:21:19 -0700
committerIvan Kohler <ivan@freeside.biz>2012-03-23 11:21:19 -0700
commit879ad5135754ec2968e39cf98f7958f0db50d359 (patch)
treeb078db36bcaf89c11cdccdb755ff662807175c97
parentbf4e71db6af0d0a86edcec8b447d8b5444d45f6c (diff)
parent9f97c81b19a3184ea68df32aaea43808b22e10f0 (diff)
Merge branch 'master' of git.freeside.biz:/home/git/freeside
-rw-r--r--FS/FS/Report/Table.pm18
-rw-r--r--FS/FS/cust_main/Search.pm9
-rw-r--r--httemplate/elements/menu.html1
-rw-r--r--httemplate/graph/cust_signup.html83
-rw-r--r--httemplate/graph/elements/monthly.html3
-rw-r--r--httemplate/graph/elements/report.html10
-rw-r--r--httemplate/graph/report_cust_signup.html37
-rwxr-xr-xhttemplate/search/cust_main.html1
8 files changed, 157 insertions, 5 deletions
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;
+}
+
+</%init>
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</A>" 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 = '<A CLASS="cell" HREF="'.$link_prefix if $link_prefix;
% $cell[$i] = [ emt('Total') ];
% for (my $e = 0; $e < $num_entries + 1; $e++) {
% my $entry = sum(map { $_->[$e] } @data);
diff --git a/httemplate/graph/report_cust_signup.html b/httemplate/graph/report_cust_signup.html
new file mode 100644
index 000000000..9d3f5006b
--- /dev/null
+++ b/httemplate/graph/report_cust_signup.html
@@ -0,0 +1,37 @@
+<% include('/elements/header.html', 'Customer Signup Summary' ) %>
+
+<FORM ACTION="cust_signup.html" METHOD="GET">
+
+<TABLE>
+
+<% 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)',
+ )
+%>
+
+</TABLE>
+
+<BR><INPUT TYPE="submit" VALUE="Display">
+</FORM>
+
+<% include('/elements/footer.html') %>
+<%init>
+
+#XXX use a different ACL for package churn?
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
+
+</%init>
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 ) {