omit charging for some services in bulk price plans, RT#24053
authorIvan Kohler <ivan@freeside.biz>
Wed, 24 Jul 2013 08:18:35 +0000 (01:18 -0700)
committerIvan Kohler <ivan@freeside.biz>
Wed, 24 Jul 2013 08:18:35 +0000 (01:18 -0700)
FS/FS/Schema.pm
FS/FS/part_pkg.pm
FS/FS/part_pkg/bulk_Common.pm
httemplate/edit/process/part_pkg.cgi
httemplate/elements/tr-pkg_svc.html

index 0b47065..40e104b 100644 (file)
@@ -2221,16 +2221,17 @@ sub tables_hashref {
 
     'pkg_svc' => {
       'columns' => [
-        'pkgsvcnum',  'serial', '',  '', '', '', 
-        'pkgpart',    'int',    '',   '', '', '', 
-        'svcpart',    'int',    '',   '', '', '', 
-        'quantity',   'int',    '',   '', '', '', 
-        'primary_svc','char', 'NULL',  1, '', '', 
-        'hidden',     'char', 'NULL',  1, '', '',
+        'pkgsvcnum',   'serial',    '', '', '', '', 
+        'pkgpart',        'int',    '', '', '', '', 
+        'svcpart',        'int',    '', '', '', '', 
+        'quantity',       'int',    '', '', '', '', 
+        'primary_svc',   'char', 'NULL', 1, '', '', 
+        'hidden',        'char', 'NULL', 1, '', '',
+        'bulk_skip',     'char', 'NULL', 1, '', '',
       ],
       'primary_key' => 'pkgsvcnum',
-      'unique' => [ ['pkgpart', 'svcpart'] ],
-      'index' => [ ['pkgpart'], ['quantity'] ],
+      'unique'      => [ ['pkgpart', 'svcpart'] ],
+      'index'       => [ ['pkgpart'], ['quantity'] ],
     },
 
     'part_referral' => {
index 0722647..15c29c4 100644 (file)
@@ -367,7 +367,9 @@ and I<options>
 If I<pkg_svc> is set to a hashref with svcparts as keys and quantities as
 values, the appropriate FS::pkg_svc records will be replaced.  I<hidden_svc>
 can be set to a hashref of svcparts and flag values ('Y' or '') to set the 
-'hidden' field in these records.
+'hidden' field in these records.  I<bulk_skip> can be set to a hashref of
+svcparts and flag values ('Y' or '') to set the 'bulk_skip' field in those
+records.
 
 If I<primary_svc> is set to the svcpart of the primary service, the appropriate
 FS::pkg_svc record will be updated.
@@ -504,10 +506,12 @@ sub replace {
   warn "  replacing pkg_svc records" if $DEBUG;
   my $pkg_svc = $options->{'pkg_svc'};
   my $hidden_svc = $options->{'hidden_svc'} || {};
+  my $bulk_skip  = $options->{'bulk_skip'} || {};
   if ( $pkg_svc ) { # if it wasn't passed, don't change existing pkg_svcs
     foreach my $part_svc ( qsearch('part_svc', {} ) ) {
-      my $quantity = $pkg_svc->{$part_svc->svcpart} || 0;
-      my $hidden = $hidden_svc->{$part_svc->svcpart} || '';
+      my $quantity  = $pkg_svc->{$part_svc->svcpart} || 0;
+      my $hidden    = $hidden_svc->{$part_svc->svcpart} || '';
+      my $bulk_skip = $bulk_skip->{$part_svc->svcpart} || '';
       my $primary_svc =
         ( defined($options->{'primary_svc'}) && $options->{'primary_svc'}
           && $options->{'primary_svc'} == $part_svc->svcpart
@@ -523,16 +527,19 @@ sub replace {
       my $old_quantity = 0;
       my $old_primary_svc = '';
       my $old_hidden = '';
+      my $old_bulk_skip = '';
       if ( $old_pkg_svc ) {
         $old_quantity = $old_pkg_svc->quantity;
         $old_primary_svc = $old_pkg_svc->primary_svc 
           if $old_pkg_svc->dbdef_table->column('primary_svc'); # is this needed?
         $old_hidden = $old_pkg_svc->hidden;
+        $old_bulk_skip = $old_pkg_svc->old_bulk_skip;
       }
    
-      next unless $old_quantity != $quantity || 
-                  $old_primary_svc ne $primary_svc ||
-                  $old_hidden ne $hidden;
+      next unless $old_quantity    != $quantity
+               || $old_primary_svc ne $primary_svc
+               || $old_hidden      ne $hidden
+               || $old_bulk_skip   ne $bulk_skip;
     
       my $new_pkg_svc = new FS::pkg_svc( {
         'pkgsvcnum'   => ( $old_pkg_svc ? $old_pkg_svc->pkgsvcnum : '' ),
@@ -541,6 +548,7 @@ sub replace {
         'quantity'    => $quantity, 
         'primary_svc' => $primary_svc,
         'hidden'      => $hidden,
+        'bulk_skip'   => $bulk_skip,
       } );
       my $error = $old_pkg_svc
                     ? $new_pkg_svc->replace($old_pkg_svc)
index 67a683a..26550df 100644 (file)
@@ -58,11 +58,17 @@ sub calc_recur {
   my %n_setup = ();
   my %n_recur = ();
   my %part_svc_label = ();
+  my %pkg_svc = ();
 
   my $summarize = $self->option('summarize_svcs',1);
 
   foreach my $cust_svc ( $self->_bulk_cust_svc( $cust_pkg, $sdate ) ) {
 
+    my $pkg_svc = $pkg_svc{ $cust_pkg->pkgpart. '_'. $cust_svc->svcpart }
+                    ||= qsearchs('pkg_svc', { 'pkgpart' => $cust_pkg->pkgpart,
+                                              'svcpart' => $cust_svc->svcpart});
+    next if $pkg_svc->bulk_skip;
+
     my @label = $cust_svc->label_long( $$sdate, $last_bill );
     die "fatal: no label found, wtf?" unless scalar(@label); #?
     my $svc_details = $label[0]. ': '. $label[1]. ': ';
index 3b6562f..db4fcb9 100755 (executable)
@@ -132,10 +132,16 @@ my $args_callback = sub {
   ###
 
   my @svcparts = map { $_->svcpart } qsearch('part_svc', {});
-  my %pkg_svc = map { $_ => scalar($cgi->param("pkg_svc$_")) } @svcparts;
-  my %hidden_svc = map { $_ => scalar($cgi->param("hidden$_")) } @svcparts;
-
-  push @args, 'pkg_svc' => \%pkg_svc, 'hidden_svc' => \%hidden_svc;
+  my %pkg_svc    = map { $_ => scalar($cgi->param("pkg_svc$_"  )) } @svcparts;
+  my %hidden_svc = map { $_ => scalar($cgi->param("hidden$_"   )) } @svcparts;
+  my %bulk_skip  = map { $_ => ( $cgi->param("no_bulk_skip$_") eq 'Y'
+                                   ? '' : 'Y'
+                               )
+                                                                  } @svcparts;
+
+  push @args, 'pkg_svc'    => \%pkg_svc,
+              'hidden_svc' => \%hidden_svc,
+              'bulk_skip'  => \%bulk_skip;
 
   ###
   # cust_pkg and custnum_ref (inserts only)
index 6d17a37..1923f12 100644 (file)
@@ -7,12 +7,15 @@
 %foreach my $part_svc ( @part_svc ) {
 %  my $svcpart = $part_svc->svcpart;
 %  my $pkg_svc = $pkg_svc{$svcpart}
-%             || new FS::pkg_svc ( {
-%                                   'pkgpart'     => $pkgpart,
-%                                   'svcpart'     => $svcpart,
-%                                   'quantity'    => 0,
-%                                   'primary_svc' => '',
-%                                   'hidden'      => '',
+%              ||= qsearchs('pkg_svc', { 'pkgpart' => $pkgpart,
+%                                        'svcpart' => $svcpart } )
+%              || new FS::pkg_svc ( {
+%                                     'pkgpart'     => $pkgpart,
+%                                     'svcpart'     => $svcpart,
+%                                     'quantity'    => 0,
+%                                     'primary_svc' => '',
+%                                     'hidden'      => '',
+%                                     'bulk_skip'   => '',
 %                                } );
 %  if ( $cgi->param('error') ) {
 %    my $primary_svc = ( $pkg_svc->primary_svc =~ /^Y/i );
@@ -23,8 +26,6 @@
 %      if ! $primary_svc && $pkg_svc_primary == $svcpart;
 %  }
 %
-%  push @fixups, "pkg_svc$svcpart";
-%
 %  my $quan = 0;
 %  if ( $cgi->param("pkg_svc$svcpart") =~ /^\s*(\d+)\s*$/ ) {
 %    $quan = $1;
 %    $quan = $pkg_svc->quantity;
 %  }
 %
+%  my $hidden = '';
+%  if ( grep { $_ eq "hidden_svc$svcpart" } $cgi->param ) {
+%    $hidden = $cgi->param("hidden_svc$svcpart");
+%  } else {
+%    $hidden = $pkg_svc->hidden;
+%  }
+%  my $bulk_skip = '';
+%  if ( grep { $_ eq "no_bulk_skip$svcpart" } $cgi->param ) {
+%    $bulk_skip = $cgi->param("no_bulk_skip$svcpart") eq 'Y' ? '' : 'Y';
+%  } else {
+%    $bulk_skip = $pkg_svc->bulk_skip;
+%  }
+%
 %  my @exports = $pkg_svc->part_svc->part_export;
 %  foreach my $export ( @exports ) {
 %      push @possible_exports, $export if $export->can('external_pkg_map');
@@ -39,7 +53,7 @@
 
   <TR>
     <TD>
-      <INPUT TYPE="text" NAME="pkg_svc<% $svcpart %>" SIZE=7 MAXLENGTH=6 VALUE="<% $quan %>">
+      <INPUT TYPE="text" NAME="pkg_svc<% $svcpart %>" SIZE=4 MAXLENGTH=6 VALUE="<% $quan %>">
     </TD>
    
     <TD ALIGN="center">
       <A HREF="part_svc.cgi?<% $part_svc->svcpart %>"><% $part_svc->svc %></A>      <% $part_svc->disabled =~ /^Y/i ? ' (DISABLED' : '' %>
     </TD>
 
-    <TD>
-      <INPUT TYPE="checkbox" NAME="hidden<% $svcpart %>" VALUE="Y"<% $pkg_svc->hidden =~ /^Y/i ? ' CHECKED' : ''%>>
+    <TD ALIGN="center">
+      <INPUT TYPE="checkbox" NAME="hidden<% $svcpart %>" VALUE="Y"<% $hidden =~ /^Y/i ? ' CHECKED' : ''%>>
     </TD>
+
+    <TD ALIGN="center">
+      <INPUT TYPE="checkbox" NAME="no_bulk_skip<% $svcpart %>" VALUE="Y"<% $bulk_skip =~ /^Y/i ? '' : ' CHECKED' %>>
+    </TD>
+
   </TR>
 % foreach ( 1 .. $columns-1 ) {
 %       if ( $count == int( $_ * scalar(@part_svc) / $columns ) ) { 
@@ -102,10 +121,12 @@ my %opt = @_;
 my $cgi = $opt{'cgi'};
 
 my $thead =  "\n\n". ntable('#cccccc', 2).
-             '<TR><TH BGCOLOR="#dcdcdc"><FONT SIZE=-1>Quan.</FONT></TH>'.
-             '<TH BGCOLOR="#dcdcdc"><FONT SIZE=-2>Primary</FONT></TH>'.
+             '<TR>'.
+             '<TH BGCOLOR="#dcdcdc"><FONT SIZE=-1>Quan.</FONT></TH>'.
+             '<TH BGCOLOR="#dcdcdc"><FONT SIZE=-1>Primary</FONT></TH>'.
              '<TH BGCOLOR="#dcdcdc">Service</TH>'.
-             '<TH BGCOLOR="#dcdcdc"><FONT SIZE=-1>Hide</FONT></TH>'.
+             '<TH BGCOLOR="#dcdcdc"><FONT SIZE=-1>Hide<BR>from<BR>Invoices</FONT></TH>'.
+             '<TH BGCOLOR="#dcdcdc"><FONT SIZE=-1>Bulk<BR>Charge</FONT></TH>'.
              '</TR>';
 
 my $part_pkg = $opt{'object'};
@@ -124,7 +145,6 @@ my @part_svc = qsearch('part_svc', {}, '', $where);
 #my %pkg_svc = map { $_->svcpart => $_ } $q_part_pkg->pkg_svc;
 my %pkg_svc = map { $_->svcpart => $_ } $part_pkg->pkg_svc('disable_linked'=>1);
 
-my @fixups = ();
 my $count = 0;
 my $columns = 3;