Merge branch 'master' of git.freeside.biz:/home/git/freeside
authorIvan Kohler <ivan@freeside.biz>
Thu, 28 Mar 2013 02:28:46 +0000 (19:28 -0700)
committerIvan Kohler <ivan@freeside.biz>
Thu, 28 Mar 2013 02:28:46 +0000 (19:28 -0700)
FS/FS/cust_pkg.pm
FS/FS/part_event/Condition/cust_bill_owed_percent.pm [new file with mode: 0644]
conf/invoice_html
conf/invoice_latex
httemplate/elements/selectlayers.html
httemplate/search/agent_commission.html
httemplate/view/cust_main/packages/location.html
httemplate/view/cust_main/packages/section.html

index 374cf7a..9e188af 100644 (file)
@@ -1781,6 +1781,12 @@ sub change {
   # (i.e. customer default location)
   $opt->{'locationnum'} = $self->locationnum if !exists($opt->{'locationnum'});
 
+  # usually this doesn't matter.  the two cases where it does are:
+  # 1. unused_credit_change + pkgpart change + setup fee on the new package
+  # and
+  # 2. (more importantly) changing a package before it's billed
+  $hash{'waive_setup'} = $self->waive_setup;
+
   # Create the new package.
   my $cust_pkg = new FS::cust_pkg {
     custnum      => $self->custnum,
diff --git a/FS/FS/part_event/Condition/cust_bill_owed_percent.pm b/FS/FS/part_event/Condition/cust_bill_owed_percent.pm
new file mode 100644 (file)
index 0000000..e06b511
--- /dev/null
@@ -0,0 +1,50 @@
+package FS::part_event::Condition::cust_bill_owed_percent;
+
+use strict;
+use FS::cust_bill;
+
+use base qw( FS::part_event::Condition );
+
+sub description {
+  'Percentage owed on specific invoice';
+}
+
+sub eventtable_hashref {
+    { 'cust_main' => 0,
+      'cust_bill' => 1,
+      'cust_pkg'  => 0,
+    };
+}
+
+sub option_fields {
+  (
+    'owed' => { 'label'      => 'Percentage of invoice owed over',
+                'type'       => 'percentage',
+                'value'      => '0', #default
+              },
+  );
+}
+
+sub condition {
+  #my($self, $cust_bill, %opt) = @_;
+  my($self, $cust_bill) = @_;
+
+  my $percent = $self->option('owed') || 0;
+  my $over = sprintf('%.2f',
+      $cust_bill->charged * $percent / 100);
+
+  $cust_bill->owed > $over;
+}
+
+sub condition_sql {
+  my( $class, $table ) = @_;
+
+  # forces the option to be an integer--do we care?
+  my $percent = $class->condition_sql_option_integer('owed');
+
+  my $owed_sql = FS::cust_bill->owed_sql;
+
+  "$owed_sql > CAST( cust_bill.charged * $percent / 100 AS DECIMAL(10,2) )";
+}
+
+1;
index 567385b..cd34827 100644 (file)
             $OUT .=  '<th align="center">' . emt('Ref') . '</th>'.
                      '<th align="left">' . emt('Description') . '</th>'.
                      ( $unitprices 
-                       ? '<th align="left">' . emt('Unit Price') . '</th>'.
-                         '<th align="left">' . emt('Quantity') . '</th>'
+                       ? '<th align="right">' . emt('Unit Price') . '</th>'.
+                         '<th align="right">' . emt('Quantity') . '</th>'
                         : '' ).
                      '<th align="right">' . emt('Amount') . '</th>';
           }
                        ( $line->{'ref'} ne $lastref ? $line->{'ref'} : '' ). '</td>'.
                        '<td align="left">'. $line->{'description'}. '</td>'.
                        ( $unitprices 
-                           ? '<td align="left">'. $line->{'unit_amount'}. '</td>'.
-                             '<td align="left">'. $line->{'quantity'}. '</td>'
+                           ? '<td align="right">'. $line->{'unit_amount'}. '</td>'.
+                             '<td align="right">'. $line->{'quantity'}. '</td>'
                            : ''
                        ).
 
index d56a7fb..533e834 100644 (file)
 \newcommand{\FSdescriptionlength} { [@-- $unitprices ? '8.2cm' : '12.8cm' --@] }\r
 \newcommand{\FSdescriptioncolumncount} { [@-- $unitprices ? '4' : '6' --@] }\r
 \newcommand{\FSunitcolumns}{ [@-- \r
-  $unitprices \r
-  ? '\makebox[2.5cm][l]{\textbf{~~'.emt('Unit Price').'}}&\makebox[1.4cm]{\textbf{~'.emt('Quantity').'}}&' \r
+  $unitprices\r
+  ? '\makebox[2.5cm][r]{\textbf{~~' . emt('Unit Price') . '}} &' .\r
+    '\makebox[1.4cm]{\textbf{~' . emt('Quantity') . '}} & ' \r
   : '' --@] }\r
 \r
 \newcommand{\FShead}{\r
 \newcommand{\FSdesc}[5]{\r
   \multicolumn{1}{c}{\rule{0pt}{2.5ex}\textbf{#1}} &\r
   \multicolumn{[@-- $unitprices ? '4' : '6' --@]}{l}{\textbf{#2}} &\r
-[@-- $unitprices ? '  \multicolumn{1}{l}{\textbf{#3}} &'."\n".\r
+[@-- $unitprices ? '  \multicolumn{1}{r}{\textbf{\dollar #3}} &'."\n".\r
                    '  \multicolumn{1}{r}{\textbf{#4}} &'."\n"\r
                  : ''\r
 --@]\r
index 01fd590..cb1d2d6 100644 (file)
@@ -236,7 +236,7 @@ sub layer_callback {
       $date_noinit = 1;
     }
     else {
-      $include = "input-$include" if $include =~ /^(text|money)$/;
+      $include = "input-$include" if $include =~ /^(text|money|percentage)$/;
       $include = "tr-$include" unless $include eq 'hidden';
       $html .= include( "/elements/$include.html",
                         %$lf,
index b8fbe20..b94ae9f 100644 (file)
@@ -1,6 +1,12 @@
 %# still not a good way to do rows grouped by some field in a search.html 
 %# report
+% if ( $type eq 'xls' ) {
+<% $data %>\
+% } 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 {
@@ -58,6 +64,7 @@ td.money:before { content: '<% $money_char %>'; }
   </TR>
 </TABLE>
 <& /elements/footer.html &>
+% }
 <%init>
 die "access denied" 
   unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
@@ -100,10 +107,91 @@ my @cust_pkg = qsearch($query);
 
 my $money_char = FS::Conf->new->config('money_char') || '$';
 
-#my $count_query = 
-#  'SELECT COUNT(*) FROM cust_pkg '.$query->{'addl_from'}.$query->{'extra_sql'}.
-#  ' AND EXISTS(SELECT 1 FROM cust_bill_pkg JOIN cust_bill USING (invnum) '.
-#    ' WHERE cust_bill_pkg.pkgnum = cust_pkg.pkgnum AND '.
-#    "cust_bill._date >= $begin AND cust_bill._date < $end".
-#  ')';
+my $data = '';
+my $type = $cgi->param('_type');
+if ( $type eq 'xls') {
+  # some false laziness with the above...
+  my $format = $FS::CurrentUser::CurrentUser->spreadsheet_format;
+  my $filename = 'agent_commission' . $format->{extension}; 
+  http_header('Content-Type' => $format->{mime_type});
+  http_header('Content-Disposition' => qq!attachment;filename="$filename"!);
+  my $XLS = IO::Scalar->new(\$data);
+  my $workbook = $format->{class}->new($XLS);
+  my $worksheet = $workbook->add_worksheet(substr($title, 0, 31));
+
+  my $cust_head_format = $workbook->add_format(
+    bold      => 1,
+    underline => 1,
+    text_wrap => 0,
+    bg_color  => 'white',
+  );
+
+  my $col_head_format = $workbook->add_format(
+    bold      => 1,
+    align     => 'center',
+    bg_color  => 'silver'
+  );
+
+  my @format;
+  foreach (0, 1) {
+    my %bg = (bg_color => $_ ? 'white' : 'silver');
+    $format[$_] = {
+      'text'    => $workbook->add_format(%bg),
+      'money'   => $workbook->add_format(%bg, num_format => $money_char.'#0.00'),
+      'percent' => $workbook->add_format(%bg, num_format => '0.00%'),
+    };
+  }
+  my $total_format = $workbook->add_format(
+    bg_color    => 'yellow',
+    num_format  => $money_char.'#0.00',
+    top         => 1
+  );
+
+  my ($r, $c) = (0, 0);
+  foreach (qw(Package Sales Percentage Commission)) {
+    $worksheet->write($r, $c++, $_, $col_head_format);
+  }
+  $r++;
+
+  my ($custnum, $sales, $commission, $row, $bgcolor) = (0, 0, 0, 0);
+  my $label_length = 0;
+  foreach my $cust_pkg ( @cust_pkg ) {
+    if ( $custnum ne $cust_pkg->custnum ) {
+      # start of a new customer section
+      my $cust_main = $cust_pkg->cust_main;
+      my $label = $cust_main->custnum . ': '. $cust_main->name;
+      $bgcolor = 0;
+      $worksheet->set_row($r, 20);
+      $worksheet->merge_range($r, 0, $r, 3, $label, $cust_head_format);
+      $r++;
+    }
+    $c = 0;
+    my $percent = $cust_pkg->percent / 100;
+    $worksheet->write($r, $c++, $cust_pkg->pkg_label, $format[$bgcolor]{text});
+    $worksheet->write($r, $c++, $cust_pkg->sum_charged, $format[$bgcolor]{money});
+    $worksheet->write($r, $c++, $percent, $format[$bgcolor]{percent});
+    $worksheet->write($r, $c++, ($cust_pkg->sum_charged * $percent),
+                                $format[$bgcolor]{money});
+
+    $label_length = max($label_length, length($cust_pkg->pkg_label));
+    $sales += $cust_pkg->sum_charged;
+    $commission += $cust_pkg->sum_charged * $cust_pkg->percent / 100;
+    $row++;
+    $bgcolor = 1-$bgcolor;
+    $custnum = $cust_pkg->custnum;
+    $r++;
+  }
+
+  $c = 0;
+  $label_length = max($label_length, 20);
+  $worksheet->set_column($c, $c, $label_length);
+  $worksheet->write($r, $c++, mt('[quant,_1,package] with commission', $row),
+                                  $total_format);
+  $worksheet->set_column($c, $c + 2, 11);
+  $worksheet->write($r, $c++, $sales, $total_format);
+  $worksheet->write($r, $c++, '', $total_format);
+  $worksheet->write($r, $c++, $commission, $total_format);
+
+  $workbook->close;
+}
 </%init>
index 34e3a64..aa3fabf 100644 (file)
@@ -1,7 +1,8 @@
 <TD CLASS="inv" BGCOLOR="<% $bgcolor %>" WIDTH="20%">
 
-% unless ( $cust_pkg->locationnum ) {
-  <I><FONT SIZE=-1>(<% mt('default service address') |h %>)</FONT><BR>
+% if ( $default ) {
+  <DIV STYLE="font-style: italic; font-size: small">
+  (<% emt('default service address') %>)<BR>
 % }
 
     <% $loc->location_label( 'join_string'     => '<BR>',
@@ -24,8 +25,8 @@
         </FONT>
 %   }
 
-% unless ( $cust_pkg->locationnum ) {
-  </I>
+% if ( $default ) {
+  </DIV>
 % }
 
 % if ( ! $cust_pkg->get('cancel')
@@ -54,6 +55,8 @@ my $statedefault   = $opt{'statedefault'}
                      || ($countrydefault eq 'US' ? 'CA' : '');
 
 my $loc = $cust_pkg->cust_location_or_main;
+# dubious--they should all have a location now
+my $default = $cust_pkg->locationnum == $opt{'cust_main'}->ship_locationnum;
 
 sub pkg_change_location_link {
   my $cust_pkg = shift;
index 5224619..8ea7a7d 100755 (executable)
@@ -84,7 +84,7 @@ my %conf_opt = (
   'manage_link_loc'           => scalar($conf->config('svc_broadband-manage_link_loc')),
   'manage_link-new_window'    => $conf->exists('svc_broadband-manage_link-new_window'),
   'maestro-status_test'       => $conf->exists('maestro-status_test'),
-  'cust_pkg-large_pkg_size'   => $conf->config('cust_pkg-large_pkg_size'),
+  'cust_pkg-large_pkg_size'   => scalar($conf->config('cust_pkg-large_pkg_size')),
 
   # for packages.html Change location link
   'show_location'             => $show_location,