[freeside-commits] branch master updated. c0c5709fb022b83a482d0b35f7094505766d5868

Mark Wells mark at 420.am
Fri Sep 18 12:01:36 PDT 2015


The branch, master has been updated
       via  c0c5709fb022b83a482d0b35f7094505766d5868 (commit)
       via  7bce756e86a4307d6cad49a690f22a321acc9981 (commit)
       via  5aafaf2e4efe3a7b57ec9afd563ced32e70b581f (commit)
      from  7ee96ef046f8e5167a4dda7c4322485549ec29c3 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit c0c5709fb022b83a482d0b35f7094505766d5868
Author: Mark Wells <mark at freeside.biz>
Date:   Fri Sep 18 10:18:43 2015 -0700

    send commission reports by email, #33101

diff --git a/FS/FS/AccessRight.pm b/FS/FS/AccessRight.pm
index 9274ad8..53c7cf6 100644
--- a/FS/FS/AccessRight.pm
+++ b/FS/FS/AccessRight.pm
@@ -288,6 +288,7 @@ tie my %rights, 'Tie::IxHash',
     'Billing event reports',
     'Receivables report',
     'Financial reports',
+    { rightname=>'Send reports to customers', global=>1 },
     { rightname=> 'List inventory', global=>1 },
     { rightname=>'View email logs', global=>1 },
     { rightname=>'View system logs' },
diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm
index ae4f07c..98a75c8 100644
--- a/FS/FS/Mason.pm
+++ b/FS/FS/Mason.pm
@@ -405,6 +405,10 @@ if ( -e $addl_handler_use_file ) {
   use FS::cust_pkg_reason_fee;
   use FS::part_svc_link;
   use FS::access_user_log;
+  use FS::report_batch;
+  use FS::report_batch;
+  use FS::report_batch;
+  use FS::report_batch;
   # Sammath Naur
 
   if ( $FS::Mason::addl_handler_use ) {
diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index 12211d1..85fbbeb 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -7124,6 +7124,37 @@ sub tables_hashref {
                         ],
     },
 
+    'report_batch' => {
+      'columns' => [
+        'reportbatchnum', 'serial',      '',  '', '', '',
+        'reportname',     'varchar',     '', 255, '', '',
+        'agentnum',           'int', 'NULL',  '', '', '',
+        'send_date',     @date_type,              '', '',
+        'sdate',         @date_type,              '', '',
+        'edate',         @date_type,              '', '',
+        'usernum',            'int', 'NULL',  '', '', '',
+        'msgnum',             'int', 'NULL',  '', '', '',
+        # add report params here as necessary
+      ],
+      'primary_key' => 'reportbatchnum',
+      'unique' => [],
+      'index'  => [],
+      'foreign_keys' => [
+                          { columns    => [ 'agentnum' ],
+                            table      => 'agent',
+                            references => [ 'agentnum' ],
+                          },
+                          { columns    => [ 'usernum' ],
+                            table      => 'access_user',
+                            references => [ 'usernum' ],
+                          },
+                          { columns    => [ 'msgnum' ],
+                            table      => 'msg_template',
+                            references => [ 'msgnum' ],
+                          },
+                        ],
+    },
+
     # name type nullability length default local
 
     #'new_table' => {
diff --git a/FS/FS/cust_bill_pkg.pm b/FS/FS/cust_bill_pkg.pm
index 8233ce0..1780426 100644
--- a/FS/FS/cust_bill_pkg.pm
+++ b/FS/FS/cust_bill_pkg.pm
@@ -1124,7 +1124,10 @@ sub tax_locationnum {
   if ( $self->pkgnum ) { # normal sales
     return $self->cust_pkg->tax_locationnum;
   } elsif ( $self->feepart ) { # fees
-    return $self->cust_bill->cust_main->ship_locationnum;
+    my $custnum = $self->fee_origin->custnum;
+    if ( $custnum ) {
+      return FS::cust_main->by_key($custnum)->ship_locationnum;
+    }
   } else { # taxes
     return '';
   }
@@ -1135,7 +1138,10 @@ sub tax_location {
   if ( $self->pkgnum ) { # normal sales
     return $self->cust_pkg->tax_location;
   } elsif ( $self->feepart ) { # fees
-    return $self->cust_bill->cust_main->ship_location;
+    my $custnum = $self->fee_origin->custnum;
+    if ( $custnum ) {
+      return FS::cust_main->by_key($custnum)->ship_location;
+    }
   } else { # taxes
     return;
   }
diff --git a/FS/FS/cust_msg.pm b/FS/FS/cust_msg.pm
index db02680..27272b8 100644
--- a/FS/FS/cust_msg.pm
+++ b/FS/FS/cust_msg.pm
@@ -148,6 +148,7 @@ sub check {
                                     'invoice',
                                     'receipt',
                                     'admin',
+                                    'report',
                                  ])
   ;
   return $error if $error;
diff --git a/FS/FS/msg_template/email.pm b/FS/FS/msg_template/email.pm
index e6d5a5a..377dbb1 100644
--- a/FS/FS/msg_template/email.pm
+++ b/FS/FS/msg_template/email.pm
@@ -200,6 +200,12 @@ A hash reference of additional substitutions
 A string identifying the kind of message this is. Currently can be "invoice", 
 "receipt", "admin", or null. Expand this list as necessary.
 
+=item override_content
+
+A string to use as the HTML body; if specified, replaces the entire
+body of the message. This should be used ONLY by L<FS::report_batch> and may
+go away in the future.
+
 =back
 
 =cut
@@ -265,6 +271,12 @@ sub prepare {
   warn "$me filling in body template\n" if $DEBUG;
   $body = $body_tmpl->fill_in( HASH => $hashref );
 
+  # override $body if requested
+  if ( $opt{'override_content'} ) {
+    warn "$me overriding template body with requested content" if $DEBUG;
+    $body = $opt{'override_content'};
+  }
+
   ###
   # and email
   ###
diff --git a/FS/FS/msg_template/http.pm b/FS/FS/msg_template/http.pm
index 51dfcff..a2b0986 100644
--- a/FS/FS/msg_template/http.pm
+++ b/FS/FS/msg_template/http.pm
@@ -59,6 +59,10 @@ sub prepare {
     %$document,
     %$hashref
   };
+  # put override content _somewhere_ so it can be used
+  if ( $opt{'override_content'} ) {
+    $document{'content'} = $opt{'override_content'};
+  }
 
   my $request_content = $json->encode($document);
   warn "$me ".$self->prepare_url."\n" if $DEBUG;
diff --git a/FS/FS/report_batch.pm b/FS/FS/report_batch.pm
new file mode 100644
index 0000000..64412df
--- /dev/null
+++ b/FS/FS/report_batch.pm
@@ -0,0 +1,321 @@
+package FS::report_batch;
+use base qw( FS::Record );
+
+use strict;
+use FS::Record qw( qsearch qsearchs dbdef );
+use FS::msg_template;
+use FS::cust_main;
+use FS::Misc::DateTime qw(parse_datetime);
+use FS::Mason qw(mason_interps);
+use URI::Escape;
+use HTML::Defang;
+
+our $DEBUG = 0;
+
+=head1 NAME
+
+FS::report_batch - Object methods for report_batch records
+
+=head1 SYNOPSIS
+
+  use FS::report_batch;
+
+  $record = new FS::report_batch \%hash;
+  $record = new FS::report_batch { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::report_batch object represents an order to send a batch of reports to
+their respective customers or other contacts.  FS::report_batch inherits from
+FS::Record.  The following fields are currently supported:
+
+=over 4
+
+=item reportbatchnum
+
+primary key
+
+=item reportname
+
+The name of the report, which will be the same as the file name (minus any
+directory names). There's an enumerated set of these; you can't use just any
+report.
+
+=item send_date
+
+The date the report was sent.
+
+=item agentnum
+
+The agentnum to limit the report to, if any.
+
+=item sdate
+
+The start date of the report period.
+
+=item edate
+
+The end date of the report period.
+
+=item usernum
+
+The user who ordered the report.
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new report batch.  To add the record to the database, see L<"insert">.
+
+=cut
+
+sub table { 'report_batch'; }
+
+=item insert
+
+Adds this record to the database.  If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Deletes this record from the database.
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database.  If there is an error,
+returns the error, otherwise returns false.
+
+=item check
+
+Checks all fields to make sure this is a valid record.  If there is
+an error, returns the error, otherwise returns false.  Called by the insert
+and replace methods.
+
+=cut
+
+sub check {
+  my $self = shift;
+
+  my $error = 
+    $self->ut_numbern('reportbatchnum')
+    || $self->ut_text('reportname')
+    || $self->ut_numbern('agentnum')
+    || $self->ut_numbern('sdate')
+    || $self->ut_numbern('edate')
+    || $self->ut_numbern('usernum')
+  ;
+  return $error if $error;
+
+  $self->set('send_date', time);
+
+  $self->SUPER::check;
+}
+
+=back
+
+=head1 SUBROUTINES
+
+=over 4
+
+=item process_send_report JOB, PARAMS
+
+Takes a hash of PARAMS, determines all contacts who need to receive a report,
+and sends it to them. On completion, creates and stores a report_batch record.
+JOB is a queue job to receive status messages.
+
+PARAMS can include:
+
+- reportname: the name of the report (listed in the C<%sendable_reports> hash).
+Required.
+- msgnum: the L<FS::msg_template> to use for this report. Currently the
+content of the template is ignored, but the subject line and From/Bcc addresses
+are still used. Required.
+- agentnum: the agent to limit the report to.
+- beginning, ending: the date range to run the report, as human-readable 
+dates (I<not> unix timestamps).
+
+=cut
+
+# trying to keep this data-driven, with parameters that tell how the report is
+# to be handled rather than callbacks.
+# - path: where under the document root the report is located
+# - domain: which table to query for objects on which the report is run.
+#   Each record in that table produces one report.
+# - cust_main: the method on that object that returns its linked customer (to
+#   which the report will be sent). If the table has a 'custnum' field, this
+#   can be omitted.
+our %sendable_reports = (
+  'sales_commission_pkg' => {
+    'name'      => 'Sales commission per package',
+    'path'      => '/search/sales_commission_pkg.html',
+    'domain'    => 'sales',
+    'cust_main' => 'sales_cust_main',
+  },
+);
+
+sub process_send_report {
+  my $job = shift;
+  my $param = shift;
+
+  my $msgnum = $param->{'msgnum'};
+  my $template = FS::msg_template->by_key($msgnum)
+    or die "msg_template $msgnum not found\n";
+
+  my $reportname = $param->{'reportname'};
+  my $info = $sendable_reports{$reportname}
+    or die "don't know how to send report '$reportname'\n";
+
+  # the most important thing: which report is it?
+  my $path = $info->{'path'};
+
+  # find all targets for the report:
+  # - those matching the agentnum if there is one.
+  # - those that aren't disabled.
+  my $domain = $info->{domain};
+  my $dbt = dbdef->table($domain);
+  my $hashref = {};
+  if ( $param->{'agentnum'} and $dbt->column('agentnum') ) {
+    $hashref->{'agentnum'} = $param->{'agentnum'};
+  }
+  if ( $dbt->column('disabled') ) {
+    $hashref->{'disabled'} = '';
+  }
+  my @records = qsearch($domain, $hashref);
+  my $num_targets = scalar(@records);
+  return if $num_targets == 0;
+  my $sent = 0;
+
+  my $outbuf;
+  my ($fs_interp) = mason_interps('standalone', 'outbuf' => \$outbuf);
+  # if generating the report fails, we want to capture the error and exit,
+  # not send it.
+  $fs_interp->error_mode('fatal');
+  $fs_interp->error_format('brief');
+
+  # we have to at least have an RT::Handle
+  require RT;
+  RT::LoadConfig();
+  RT::Init();
+
+  # hold onto all the reports until we're sure they generated correctly.
+  my %cust_main;
+  my %report_content;
+
+  # grab the stylesheet
+  ### note: if we need the ability to support different stylesheets, this
+  ### is the place to put it in
+  eval { $fs_interp->exec('/elements/freeside.css') };
+  die "couldn't load stylesheet via Mason: $@\n" if $@;
+  my $stylesheet = $outbuf;
+
+  my $pkey = $dbt->primary_key;
+  foreach my $rec (@records) {
+
+    $job->update_statustext(int( 100 * $sent / $num_targets ));
+    my $pkey_val = $rec->get($pkey); # e.g. sales.salesnum
+
+    # find the customer we're sending to, and their email
+    my $cust_main;
+    if ( $info->{'cust_main'} ) {
+      my $cust_method = $info->{'cust_main'};
+      $cust_main = $rec->$cust_method;
+    } elsif ( $rec->custnum ) {
+      $cust_main = FS::cust_main->by_key($rec->custnum);
+    } else {
+      warn "$pkey = $pkey_val has no custnum; not sending report\n";
+      next;
+    }
+    my @email = $cust_main->invoicing_list_emailonly;
+    if (!@email) {
+      warn "$pkey = $pkey_val has no email destinations\n" if $DEBUG;
+      next;
+    }
+
+    # params to send to the report (as if from the user's browser)
+    my @report_param = ( # maybe list these in $info
+      agentnum  => $param->{'agentnum'},
+      beginning => $param->{'beginning'},
+      ending    => $param->{'ending'},
+      $pkey     => $pkey_val,
+      _type     => 'html-print',
+    );
+
+    # build a query string
+    my $query_string = '';
+    while (@report_param) {
+      $query_string .= uri_escape(shift @report_param)
+                    .  '='
+                    .  uri_escape(shift @report_param);
+      $query_string .= ';' if @report_param;
+    }
+    warn "$path?$query_string\n\n" if $DEBUG;
+
+    # run the report!
+    $FS::Mason::Request::QUERY_STRING = $query_string;
+    $FS::Mason::Request::FSURL = '';
+    $outbuf = '';
+    eval { $fs_interp->exec($path) };
+    die "creating report for $pkey = $pkey_val: $@" if $@;
+
+    # make some adjustments to the report
+    my $html_defang;
+    $html_defang = HTML::Defang->new(
+      url_callback      => sub { 1 }, # strip all URLs (they're not accessible)
+      tags_to_callback  => [ 'body' ], # and after the BODY tag...
+      tags_callback     => sub {
+        my $isEndTag = $_[4];
+        $html_defang->add_to_output("\n<style>\n$stylesheet\n</style>\n")
+          unless $isEndTag;
+      },
+    );
+    $outbuf = $html_defang->defang($outbuf);
+
+    $cust_main{ $cust_main->custnum } = $cust_main;
+    $report_content{ $cust_main->custnum } = $outbuf;
+  } # foreach $rec
+
+  $job->update_statustext('Sending reports...');
+  foreach my $custnum (keys %cust_main) {
+    # create an email message with the report as body
+    # change this when backporting to 3.x
+    $template->send(
+      cust_main         => $cust_main{$custnum},
+      object            => $cust_main{$custnum},
+      msgtype           => 'report',
+      override_content  => $report_content{$custnum},
+    );
+  }
+
+  my $self = FS::report_batch->new({
+    reportname  => $param->{'reportname'},
+    agentnum    => $param->{'agentnum'},
+    sdate       => parse_datetime($param->{'beginning'}),
+    edate       => parse_datetime($param->{'ending'}),
+    usernum     => $job->usernum,
+    msgnum      => $param->{'msgnum'},
+  });
+  my $error = $self->insert;
+  warn "error recording completion of report: $error\n" if $error;
+
+}
+
+=head1 SEE ALSO
+
+L<FS::Record>
+
+=cut
+
+1;
+
diff --git a/FS/MANIFEST b/FS/MANIFEST
index 5b73b72..5041ccd 100644
--- a/FS/MANIFEST
+++ b/FS/MANIFEST
@@ -850,3 +850,11 @@ FS/part_svc_link.pm
 t/part_svc_link.t
 FS/access_user_log.pm
 t/access_user_log.t
+FS/report_batch.pm
+t/report_batch.t
+FS/report_batch.pm
+t/report_batch.t
+FS/report_batch.pm
+t/report_batch.t
+FS/report_batch.pm
+t/report_batch.t
diff --git a/FS/t/report_batch.t b/FS/t/report_batch.t
new file mode 100644
index 0000000..42fc893
--- /dev/null
+++ b/FS/t/report_batch.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::report_batch;
+$loaded=1;
+print "ok 1\n";
diff --git a/httemplate/elements/popup_link-send_report_batch.html b/httemplate/elements/popup_link-send_report_batch.html
new file mode 100644
index 0000000..5f44710
--- /dev/null
+++ b/httemplate/elements/popup_link-send_report_batch.html
@@ -0,0 +1,28 @@
+<%doc>
+
+Example:
+
+<& /elements/popup_link-send_report_batch.html,
+  reportname => 'sales_commission_pkg',
+  label => 'Click here to send reports by email',
+&>
+</%doc>
+<& /elements/popup_link.html, $params &>\
+<%init>
+
+my $params = { 'closetext' => emt('Close') };
+
+if (ref($_[0]) eq 'HASH') {
+  $params = { %$params, %{ $_[0] } };
+} else {
+  $params = { %$params, @_ };
+}
+
+$params->{'label'} ||= emt('Send reports by email');
+$params->{'actionlabel'} ||= emt('Send reports');
+#$params->{'width'} ||= 350;
+$params->{'height'} ||= 650;
+
+$params->{'action'} = $fsurl. 'misc/send-report.html?reportname='. $params->{'reportname'};
+
+</%init>
diff --git a/httemplate/misc/process/send-report.html b/httemplate/misc/process/send-report.html
new file mode 100644
index 0000000..3bceebc
--- /dev/null
+++ b/httemplate/misc/process/send-report.html
@@ -0,0 +1,7 @@
+<%init>
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right('Send reports to customers');
+
+my $server = FS::UI::Web::JSRPC->new('FS::report_batch::process_send_report', $cgi);
+</%init>
+<% $server->process %>
diff --git a/httemplate/misc/send-report.html b/httemplate/misc/send-report.html
new file mode 100644
index 0000000..557767a
--- /dev/null
+++ b/httemplate/misc/send-report.html
@@ -0,0 +1,166 @@
+<%doc>
+
+Parameters:
+
+- reportname: the report name (per FS::report_batch)
+
+</%doc>
+<& /elements/header-popup.html, { title => $report_info->{name} } &>
+<script type="text/javascript">
+
+$().ready(function() {
+  var agent_info = <% encode_json(\%agent) %>;
+
+  $('#agentnum').on('change', function() {
+    var agentnum = this.value;
+    if ( agent_info[agentnum] ) {
+      $('#msgnum').prop('value',         agent_info[agentnum]['msgnum']);
+      $('#beginning_text').prop('value', agent_info[agentnum]['beginning']);
+      $('#ending_text').prop('value',    agent_info[agentnum]['ending']);
+    } else {
+      $('#msgnum').prop('value',         '');
+      $('#beginning_text').prop('value', '');
+      $('#ending_text').prop('value',    '');
+    }
+  });
+
+  $('#agentnum').trigger('change');
+
+});
+
+</script>
+<FORM NAME="OneTrueForm" ACTION="process/send-report.html" METHOD="POST">
+
+<table class="inv">
+  <input type="hidden" name="reportname" value="<% $cgi->param('reportname') |h %>">
+
+  <& /elements/tr-select-agent.html &>
+
+  <& /elements/tr-td-label.html, label => emt('Message template') &>
+    <TD>
+      <& /elements/select-msg_template.html, field => 'msgnum' &>
+    </TD>
+  </TR>
+
+  <& /elements/tr-input-beginning_ending.html &>
+
+  <& /elements/progress-init.html,
+    'OneTrueForm',
+    [ qw( reportname msgnum agentnum beginning ending ) ],
+    $p.'misc/process/send-report.html',
+    { message => 'Reports sent',
+      url => $cgi->referer }
+  &>
+
+</table>
+
+<INPUT TYPE="button" onclick="process()" VALUE="<% emt('Send reports') %>" />
+</FORM>
+
+<style>
+table.grid {
+  border-collapse: collapse;
+  margin-top: 1ex;
+  margin-left: auto;
+  margin-right: auto;
+}
+.grid caption {
+  font-weight: bold;
+  margin-bottom: 0.5ex;
+}
+.grid th,td {
+  padding-left: 3px;
+  padding-right: 3px;
+  padding-bottom: 2px;
+  border: none;
+  empty-cells: show;
+}
+.grid th {
+  border-bottom: 1px solid #999999;
+  font-size: 90%;
+  vertical-align: bottom;
+}
+</style>
+
+% if ( @report_history ) {
+<hr>
+<table class="grid">
+<caption><% emt('Report history') %></caption>
+<thead>
+  <th>Agent</th>
+  <th>Sent on</th>
+  <th colspan=2>Date range</th>
+  <th>User</th>
+</thead>
+<tbody>
+%   my $row = 0;
+%   foreach my $report (@report_history) {
+%   my $agent = ($report->agentnum ?
+%                 $report->agent->agent : 'All agents');
+  <tr class="row<% $row % 2 %>">
+    <td><% $agent %></td>
+    <td><% time2str($date_format, $report->send_date) %></td>
+    <td><% time2str($date_format, $report->sdate) %></td>
+    <td><% time2str($date_format, $report->edate) %></td>
+    <td><% $report->access_user->username %></td>
+  </tr>
+%   $row++;
+%   }
+</tbody>
+</table>
+% }
+
+<& /elements/footer.html &>
+
+<%init>
+
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right('Send reports to customers');
+
+$cgi->param('reportname') =~ /^(\w+)$/
+  or die "bad reportname";
+my $reportname = $1;
+my $report_info = $FS::report_batch::sendable_reports{$reportname}
+  or die "bad reportname";
+
+my $date_format = FS::Conf->new->config('date_format') || '%x';
+
+my @report_history = qsearch({
+  table     => 'report_batch',
+  hashref   => { reportname => $reportname },
+  order_by  => ' ORDER BY send_date DESC',
+});
+
+# defaults per agent that could be selected for the report
+my %agent;
+
+foreach my $report ( @report_history ) {
+  my $agentnum = $report->agentnum;
+  next if $agent{$agentnum};
+
+  # estimate the width of the report period, in months
+  my $last_sdate = DateTime->from_epoch( epoch => $report->sdate );
+  my $last_edate = DateTime->from_epoch( epoch => $report->edate );
+
+  my $days = $last_sdate->delta_days( $last_edate )->delta_days;
+  my $months = sprintf('%.0f', $days / 6) / 5;
+
+  my $next_sdate = $last_edate->clone->add(days => 1);
+  my $next_edate = $next_sdate->clone;
+  if ( $months >= 1 ) { # then treat as an interval in months
+    $next_edate->add( months => sprintf('%.0f', $months) );
+    $next_edate->subtract(days => 1);
+  } else { # treat as a number of days
+    $next_edate->add( days => $days );
+  }
+
+  my $name = $agentnum ? FS::agent->by_key($agentnum)->agent : 'All agents';
+  $agent{$agentnum} = {
+    name      => $name,
+    beginning => $next_sdate->strftime($date_format),
+    ending    => $next_edate->strftime($date_format),
+    msgnum    => $report->msgnum,
+  };
+}
+
+</%init>
diff --git a/httemplate/search/cust_msg.html b/httemplate/search/cust_msg.html
index 401f52e..e9aece2 100644
--- a/httemplate/search/cust_msg.html
+++ b/httemplate/search/cust_msg.html
@@ -144,11 +144,12 @@ include('/elements/select.html',
 include('/elements/select.html',
   'field' => 'msgtype',
   'curr_value' => $cgi->param('msgtype') || '',
-  'options' => [ '', 'invoice', 'receipt', 'admin' ],
+  'options' => [ '', 'invoice', 'receipt', 'admin', 'report' ],
   'labels'  => { ''         => '(any)',
                  'invoice'  => 'Invoices',
                  'receipt'  => 'Receipts',
                  'admin'    => 'Admin notices',
+                 'report'   => 'Reports',
                },
 ) .
 '</TD>
diff --git a/httemplate/search/report_sales_commission_pkg.html b/httemplate/search/report_sales_commission_pkg.html
index 6adf090..27906e0 100644
--- a/httemplate/search/report_sales_commission_pkg.html
+++ b/httemplate/search/report_sales_commission_pkg.html
@@ -1,5 +1,15 @@
 <& /elements/header.html, 'Sales commission report per package' &>
 
+% if ($FS::CurrentUser::CurrentUser->access_right('Send reports to customers'))
+%   {
+<P>
+<& /elements/popup_link-send_report_batch.html,
+    reportname => 'sales_commission_pkg',
+    label => emt('Send these reports by email'),
+&>
+</P>
+% } 
+
 <FORM ACTION="sales_commission_pkg.html">
 
 <TABLE BGCOLOR="#cccccc" CELLSPACING=0>
diff --git a/httemplate/search/sales_commission_pkg.html b/httemplate/search/sales_commission_pkg.html
index 2b5f2bb..9fbe22e 100644
--- a/httemplate/search/sales_commission_pkg.html
+++ b/httemplate/search/sales_commission_pkg.html
@@ -1,12 +1,17 @@
 %# still not a good way to do rows grouped by some field in a search.html 
 %# report
+%# (there is now, but we're not yet sponsored to switch this over to it)
 % if ( $type eq 'xls' ) {
 <% $data %>\
 % } else {
+%   if ( $type eq 'html-print' ) {
+<& /elements/header-popup.html, $title &>
+%   } else {
 <& /elements/header.html, $title &>
 <P ALIGN="right" CLASS="noprint">
 Download full results<BR>
 as <A HREF="<% $cgi->self_url %>;_type=xls">Excel spreadsheet</A></P>
+%   }
 <BR>
 <STYLE TYPE="text/css">
 td.cust_head {
@@ -22,12 +27,14 @@ td.money:before { content: '<% $money_char %>'; }
 .row1 { background-color: #ffffff; }
 </STYLE>
 <& /elements/table-grid.html &>
+<THEAD>
   <TR STYLE="background-color: #cccccc">
     <TH CLASS="grid">Package</TH>
     <TH CLASS="grid">Sales</TH>
     <TH CLASS="grid">Percentage</TH>
     <TH CLASS="grid">Commission</TH>
   </TR>
+</THEAD>
 % my ($custnum, $sales, $commission, $row, $bgcolor) = (0, 0, 0, 0);
 % foreach my $cust_pkg ( @cust_pkg ) {
 %   if ( $custnum ne $cust_pkg->custnum ) {

commit 7bce756e86a4307d6cad49a690f22a321acc9981
Merge: 5aafaf2 7ee96ef
Author: Mark Wells <mark at freeside.biz>
Date:   Fri Sep 18 10:18:16 2015 -0700

    Merge branch 'master' of git.freeside.biz:/home/git/freeside


commit 5aafaf2e4efe3a7b57ec9afd563ced32e70b581f
Author: Mark Wells <mark at freeside.biz>
Date:   Fri Sep 18 00:40:10 2015 -0700

    fix HTML

diff --git a/httemplate/elements/tr-td-label.html b/httemplate/elements/tr-td-label.html
index 78690f1..f706722 100644
--- a/httemplate/elements/tr-td-label.html
+++ b/httemplate/elements/tr-td-label.html
@@ -9,7 +9,7 @@ Actually <TR> <TH> $label </TH>
       VALIGN = "<% $opt{'valign'} || 'top' %>"
       STYLE  = "<% $style %>"
       ID     = "<% $opt{label_id} || $opt{id}. '_label0' %>"
-  ><% $required %><% $opt{label} %></TD>
+  ><% $required %><% $opt{label} %></TH>
 
 <%init>
 

-----------------------------------------------------------------------

Summary of changes:
 FS/FS/AccessRight.pm                               |    1 +
 FS/FS/Mason.pm                                     |    4 +
 FS/FS/Schema.pm                                    |   31 ++
 FS/FS/cust_bill_pkg.pm                             |   10 +-
 FS/FS/cust_msg.pm                                  |    1 +
 FS/FS/msg_template/email.pm                        |   12 +
 FS/FS/msg_template/http.pm                         |    4 +
 FS/FS/report_batch.pm                              |  321 ++++++++++++++++++++
 FS/MANIFEST                                        |    8 +
 FS/t/{AccessRight.t => report_batch.t}             |    2 +-
 .../elements/popup_link-send_report_batch.html     |   28 ++
 httemplate/elements/tr-td-label.html               |    2 +-
 httemplate/misc/process/send-report.html           |    7 +
 httemplate/misc/send-report.html                   |  166 ++++++++++
 httemplate/search/cust_msg.html                    |    3 +-
 httemplate/search/report_sales_commission_pkg.html |   10 +
 httemplate/search/sales_commission_pkg.html        |    7 +
 17 files changed, 612 insertions(+), 5 deletions(-)
 create mode 100644 FS/FS/report_batch.pm
 copy FS/t/{AccessRight.t => report_batch.t} (82%)
 create mode 100644 httemplate/elements/popup_link-send_report_batch.html
 create mode 100644 httemplate/misc/process/send-report.html
 create mode 100644 httemplate/misc/send-report.html




More information about the freeside-commits mailing list