CDR type separation and summary formats, #15535
[freeside.git] / FS / FS / part_pkg.pm
index 1dfa1ef..1db5a70 100644 (file)
@@ -277,19 +277,20 @@ sub insert {
   }
 
   if ( $options{'part_pkg_vendor'} ) {
-      my($exportnum,$vendor_pkg_id);
-      my %options_part_pkg_vendor = $options{'part_pkg_vendor'};
-      while(($exportnum,$vendor_pkg_id) = each %options_part_pkg_vendor){
-           my $ppv = new FS::part_pkg_vendor( {
-                   'pkgpart' => $self->pkgpart,
-                   'exportnum' => $exportnum,
-                   'vendor_pkg_id' => $vendor_pkg_id, 
-               } );
-           my $error = $ppv->insert;
-           if ( $error ) {
-             $dbh->rollback if $oldAutoCommit;
-             return "Error inserting part_pkg_vendor record: $error";
-           }
+      while ( my ($exportnum, $vendor_pkg_id) =
+                each %{ $options{part_pkg_vendor} }
+            )
+      {
+            my $ppv = new FS::part_pkg_vendor( {
+                    'pkgpart' => $self->pkgpart,
+                    'exportnum' => $exportnum,
+                    'vendor_pkg_id' => $vendor_pkg_id, 
+                } );
+            my $error = $ppv->insert;
+            if ( $error ) {
+              $dbh->rollback if $oldAutoCommit;
+              return "Error inserting part_pkg_vendor record: $error";
+            }
       }
   }
 
@@ -456,48 +457,48 @@ sub replace {
   if ( $options->{'part_pkg_vendor'} ) {
       my($exportnum,$vendor_pkg_id);
       while ( ($exportnum,$vendor_pkg_id) 
-                               = each %{$options->{'part_pkg_vendor'}} ) {
-         my $noinsert = 0;
-         foreach my $part_pkg_vendor ( @part_pkg_vendor ) {
-           if($exportnum == $part_pkg_vendor->exportnum
-               && $vendor_pkg_id ne $part_pkg_vendor->vendor_pkg_id) {
-               $part_pkg_vendor->vendor_pkg_id($vendor_pkg_id);
-               my $error = $part_pkg_vendor->replace;
-               if ( $error ) {
-                 $dbh->rollback if $oldAutoCommit;
-                 return "Error replacing part_pkg_vendor record: $error";
-               }
-               $noinsert = 1;
-               last;
-           }
-           elsif($exportnum == $part_pkg_vendor->exportnum
-               && $vendor_pkg_id eq $part_pkg_vendor->vendor_pkg_id) {
-               $noinsert = 1;
-               last;
-           }
-         }
-         unless ( $noinsert ) {
-           my $ppv = new FS::part_pkg_vendor( {
-                   'pkgpart' => $new->pkgpart,
-                   'exportnum' => $exportnum,
-                   'vendor_pkg_id' => $vendor_pkg_id, 
-               } );
-           my $error = $ppv->insert;
-           if ( $error ) {
-             $dbh->rollback if $oldAutoCommit;
-             return "Error inserting part_pkg_vendor record: $error";
-           }
-         }
-         push @current_exportnum, $exportnum;
+                                = each %{$options->{'part_pkg_vendor'}} ) {
+          my $noinsert = 0;
+          foreach my $part_pkg_vendor ( @part_pkg_vendor ) {
+            if($exportnum == $part_pkg_vendor->exportnum
+                && $vendor_pkg_id ne $part_pkg_vendor->vendor_pkg_id) {
+                $part_pkg_vendor->vendor_pkg_id($vendor_pkg_id);
+                my $error = $part_pkg_vendor->replace;
+                if ( $error ) {
+                  $dbh->rollback if $oldAutoCommit;
+                  return "Error replacing part_pkg_vendor record: $error";
+                }
+                $noinsert = 1;
+                last;
+            }
+            elsif($exportnum == $part_pkg_vendor->exportnum
+                && $vendor_pkg_id eq $part_pkg_vendor->vendor_pkg_id) {
+                $noinsert = 1;
+                last;
+            }
+          }
+          unless ( $noinsert ) {
+            my $ppv = new FS::part_pkg_vendor( {
+                    'pkgpart' => $new->pkgpart,
+                    'exportnum' => $exportnum,
+                    'vendor_pkg_id' => $vendor_pkg_id, 
+                } );
+            my $error = $ppv->insert;
+            if ( $error ) {
+              $dbh->rollback if $oldAutoCommit;
+              return "Error inserting part_pkg_vendor record: $error";
+            }
+          }
+          push @current_exportnum, $exportnum;
       }
   }
   foreach my $part_pkg_vendor ( @part_pkg_vendor ) {
       unless ( grep($_ eq $part_pkg_vendor->exportnum, @current_exportnum) ) {
-       my $error = $part_pkg_vendor->delete;
-       if ( $error ) {
-         $dbh->rollback if $oldAutoCommit;
-         return "Error deleting part_pkg_vendor record: $error";
-       }
+        my $error = $part_pkg_vendor->delete;
+        if ( $error ) {
+          $dbh->rollback if $oldAutoCommit;
+          return "Error deleting part_pkg_vendor record: $error";
+        }
       }
   }
 
@@ -552,6 +553,8 @@ sub check {
     || $self->ut_enum('disabled', [ '', 'Y' ] )
     || $self->ut_enum('custom', [ '', 'Y' ] )
     || $self->ut_enum('no_auto', [ '', 'Y' ])
+    || $self->ut_enum('recur_show_zero', [ '', 'Y' ])
+    || $self->ut_enum('setup_show_zero', [ '', 'Y' ])
     #|| $self->ut_moneyn('setup_cost')
     #|| $self->ut_moneyn('recur_cost')
     || $self->ut_floatn('setup_cost')
@@ -848,10 +851,7 @@ Returns true if this package is free.
 
 sub is_free {
   my $self = shift;
-  unless ( $self->plan ) {
-    $self->setup =~ /^\s*0+(\.0*)?\s*$/
-      && $self->recur =~ /^\s*0+(\.0*)?\s*$/;
-  } elsif ( $self->can('is_free_options') ) {
+  if ( $self->can('is_free_options') ) {
     not grep { $_ !~ /^\s*0*(\.0*)?\s*$/ }
          map { $self->option($_) } 
              $self->is_free_options;
@@ -864,6 +864,8 @@ sub is_free {
 
 sub can_discount { 0; }
 
+sub can_start_date { 1; }
+
 sub freqs_href {
   # moved to FS::Misc to make this accessible to other packages
   # at initialization
@@ -1064,6 +1066,10 @@ sub self_and_bill_linked {
   shift->_self_and_linked('bill', @_);
 }
 
+sub self_and_svc_linked {
+  shift->_self_and_linked('svc', @_);
+}
+
 sub _self_and_linked {
   my( $self, $type, $hidden ) = @_;
   $hidden ||= '';
@@ -1278,38 +1284,11 @@ sub _rebless {
   $self;
 }
 
-#fallbacks that eval the setup and recur fields, for backwards compat
-
-sub calc_setup {
-  my $self = shift;
-  warn 'no price plan class for '. $self->plan. ", eval-ing setup\n";
-  $self->_calc_eval('setup', @_);
-}
-
-sub calc_recur {
-  my $self = shift;
-  warn 'no price plan class for '. $self->plan. ", eval-ing recur\n";
-  $self->_calc_eval('recur', @_);
-}
-
-use vars qw( $sdate @details );
-sub _calc_eval {
-  #my( $self, $field, $cust_pkg ) = @_;
-  my( $self, $field, $cust_pkg, $sdateref, $detailsref ) = @_;
-  *sdate = $sdateref;
-  *details = $detailsref;
-  $self->$field() =~ /^(.*)$/
-    or die "Illegal $field (pkgpart ". $self->pkgpart. '): '.
-            $self->$field(). "\n";
-  my $prog = $1;
-  return 0 if $prog =~ /^\s*$/;
-  my $value = eval $prog;
-  die $@ if $@;
-  $value;
-}
+#fatal fallbacks
+sub calc_setup { die 'no calc_setup for '. shift->plan. "\n"; }
+sub calc_recur { die 'no calc_recur for '. shift->plan. "\n"; }
 
 #fallback that return 0 for old legacy packages with no plan
-
 sub calc_remain { 0; }
 sub calc_cancel { 0; }
 sub calc_units  { 0; }
@@ -1317,6 +1296,9 @@ sub calc_units  { 0; }
 #fallback for everything except bulk.pm
 sub hide_svc_detail { 0; }
 
+#fallback for packages that can't/won't summarize usage
+sub sum_usage { 0; }
+
 =item recur_cost_permonth CUST_PKG
 
 recur_cost divided by freq (only supported for monthly and longer frequencies)
@@ -1482,6 +1464,40 @@ sub _upgrade_data { # class method
       die $error if $error;
     }
   }
+
+  # migrate use_disposition_taqua and use_disposition to disposition_in
+  @part_pkg_option = qsearch('part_pkg_option',
+    { 'optionname'  => { op => 'LIKE',
+                         value => 'use_disposition%',
+                       },
+      'optionvalue' => 1,
+    });
+  my %newopts = map { $_->pkgpart => $_ } 
+    qsearch('part_pkg_option',  { 'optionname'  => 'disposition_in', } );
+  foreach my $old_opt (@part_pkg_option) {
+        my $pkgpart = $old_opt->pkgpart;
+        my $newval = $old_opt->optionname eq 'use_disposition_taqua' ? '100' 
+                                                                  : 'ANSWERED';
+        my $error = $old_opt->delete;
+        die $error if $error;
+
+        if ( exists($newopts{$pkgpart}) ) {
+            my $opt = $newopts{$pkgpart};
+            $opt->optionvalue($opt->optionvalue.",$newval");
+            $error = $opt->replace;
+            die $error if $error;
+        } else {
+            my $new_opt = new FS::part_pkg_option {
+                'pkgpart'     => $pkgpart,
+                'optionname'  => 'disposition_in',
+                'optionvalue' => $newval,
+              };
+              $error = $new_opt->insert;
+              die $error if $error;
+              $newopts{$pkgpart} = $new_opt;
+        }
+  }
+
 }
 
 =item curuser_pkgs_sql
@@ -1594,6 +1610,10 @@ foreach my $name (keys(%info)) {
   my $parents = $info{$name}->{'inherit_fields'} || [];
   my (%fields, %field_exists, @fieldorder);
   foreach my $parent ($name, @$parents) {
+    if ( !exists($info{$parent}) ) {
+      warn "$name tried to inherit from nonexistent '$parent'\n";
+      next;
+    }
     %fields = ( # avoid replacing existing fields
       %{ $info{$parent}->{'fields'} || {} },
       %fields
@@ -1603,7 +1623,8 @@ foreach my $name (keys(%info)) {
       next if $field_exists{$_};
       $field_exists{$_} = 1;
       # allow inheritors to remove inherited fields from the fieldorder
-      push @fieldorder, $_ if !exists($fields{$_}->{'disabled'});
+      push @fieldorder, $_ if !exists($fields{$_}) or
+                              !exists($fields{$_}->{'disabled'});
     }
   }
   $plans{$name}->{'fields'} = \%fields;