restrict additinal package order option, RT#6029
[freeside.git] / FS / FS / part_pkg.pm
index 0562a6d..70dcd49 100644 (file)
@@ -1,7 +1,7 @@
 package FS::part_pkg;
 
 use strict;
-use vars qw( @ISA %plans $DEBUG $setup_hack );
+use vars qw( @ISA %plans $DEBUG $setup_hack $skip_pkg_svc_hack );
 use Carp qw(carp cluck confess);
 use Scalar::Util qw( blessed );
 use Time::Local qw( timelocal_nocheck );
@@ -23,6 +23,7 @@ use FS::part_pkg_link;
 @ISA = qw( FS::m2m_Common FS::option_Common );
 $DEBUG = 0;
 $setup_hack = 0;
+$skip_pkg_svc_hack = 0;
 
 =head1 NAME
 
@@ -217,26 +218,30 @@ sub insert {
     }
   }
 
-  warn "  inserting pkg_svc records" if $DEBUG;
-  my $pkg_svc = $options{'pkg_svc'} || {};
-  foreach my $part_svc ( qsearch('part_svc', {} ) ) {
-    my $quantity = $pkg_svc->{$part_svc->svcpart} || 0;
-    my $primary_svc =
-      ( $options{'primary_svc'} && $options{'primary_svc'}==$part_svc->svcpart )
-        ? 'Y'
-        : '';
-
-    my $pkg_svc = new FS::pkg_svc( {
-      'pkgpart'     => $self->pkgpart,
-      'svcpart'     => $part_svc->svcpart,
-      'quantity'    => $quantity, 
-      'primary_svc' => $primary_svc,
-    } );
-    my $error = $pkg_svc->insert;
-    if ( $error ) {
-      $dbh->rollback if $oldAutoCommit;
-      return $error;
+  unless ( $skip_pkg_svc_hack ) {
+
+    warn "  inserting pkg_svc records" if $DEBUG;
+    my $pkg_svc = $options{'pkg_svc'} || {};
+    foreach my $part_svc ( qsearch('part_svc', {} ) ) {
+      my $quantity = $pkg_svc->{$part_svc->svcpart} || 0;
+      my $primary_svc =
+        ( $options{'primary_svc'} && $options{'primary_svc'}==$part_svc->svcpart )
+          ? 'Y'
+          : '';
+
+      my $pkg_svc = new FS::pkg_svc( {
+        'pkgpart'     => $self->pkgpart,
+        'svcpart'     => $part_svc->svcpart,
+        'quantity'    => $quantity, 
+        'primary_svc' => $primary_svc,
+      } );
+      my $error = $pkg_svc->insert;
+      if ( $error ) {
+        $dbh->rollback if $oldAutoCommit;
+        return $error;
+      }
     }
+
   }
 
   if ( $options{'cust_pkg'} ) {
@@ -369,7 +374,7 @@ sub replace {
   foreach my $part_svc ( qsearch('part_svc', {} ) ) {
     my $quantity = $pkg_svc->{$part_svc->svcpart} || 0;
     my $primary_svc =
-      ( defined($options->{'primary_svc'})
+      ( defined($options->{'primary_svc'}) && $options->{'primary_svc'}
         && $options->{'primary_svc'} == $part_svc->svcpart
       )
         ? 'Y'
@@ -460,6 +465,8 @@ sub check {
     || $self->ut_floatn('pay_weight')
     || $self->ut_floatn('credit_weight')
     || $self->ut_numbern('taxproductnum')
+    || $self->ut_foreign_keyn('classnum',       'pkg_class', 'classnum')
+    || $self->ut_foreign_keyn('addon_classnum', 'pkg_class', 'classnum')
     || $self->ut_foreign_keyn('taxproductnum',
                               'part_pkg_taxproduct',
                               'taxproductnum'
@@ -472,13 +479,6 @@ sub check {
   ;
   return $error if $error;
 
-  if ( $self->classnum !~ /^$/ ) {
-    my $error = $self->ut_foreign_key('classnum', 'pkg_class', 'classnum');
-    return $error if $error;
-  } else {
-    $self->classnum('');
-  }
-
   return 'Unknown plan '. $self->plan
     unless exists($plans{$self->plan});
 
@@ -531,6 +531,22 @@ sub pkg_class {
   }
 }
 
+=item addon_pkg_class
+
+Returns the add-on package class, as an FS::pkg_class object, or the empty
+string if there is no add-on package class.
+
+=cut
+
+sub addon_pkg_class {
+  my $self = shift;
+  if ( $self->addon_classnum ) {
+    qsearchs('pkg_class', { 'classnum' => $self->addon_classnum } );
+  } else {
+    return '';
+  }
+}
+
 =item categoryname 
 
 Returns the package category name, or the empty string if there is no package
@@ -561,6 +577,21 @@ sub classname {
     : '';
 }
 
+=item addon_classname 
+
+Returns the add-on package class name, or the empty string if there is no
+add-on package class.
+
+=cut
+
+sub addon_classname {
+  my $self = shift;
+  my $pkg_class = $self->addon_pkg_class;
+  $pkg_class
+    ? $pkg_class->classname
+    : '';
+}
+
 =item agent 
 
 Returns the associated agent for this event, if any, as an FS::agent object.
@@ -917,10 +948,12 @@ sub svc_part_pkg_link {
 
 sub _part_pkg_link {
   my( $self, $type ) = @_;
-  qsearch('part_pkg_link', { 'src_pkgpart' => $self->pkgpart,
-                             'link_type'   => $type,
-                           }
-         );
+  qsearch({ table    => 'part_pkg_link',
+            hashref  => { 'src_pkgpart' => $self->pkgpart,
+                          'link_type'   => $type,
+                        },
+            order_by => "ORDER BY hidden",
+         });
 }
 
 sub self_and_bill_linked {
@@ -928,12 +961,18 @@ sub self_and_bill_linked {
 }
 
 sub _self_and_linked {
-  my( $self, $type ) = @_;
+  my( $self, $type, $hidden ) = @_;
+  $hidden ||= '';
+
+  my @result = ();
+  foreach ( ( $self, map { $_->dst_pkg->_self_and_linked($type, $_->hidden) }
+                     $self->_part_pkg_link($type) ) )
+  {
+    $_->hidden($hidden) if $hidden;
+    push @result, $_;
+  }
 
-  ( $self,
-    map { $_->dst_pkg->_self_and_linked($type) }
-        $self->_part_pkg_link($type)
-  );
+  (@result);
 }
 
 =item part_pkg_taxoverride [ CLASS ]
@@ -1225,27 +1264,29 @@ sub _upgrade_data { # class method
   foreach my $part_pkg (@part_pkg) {
 
     unless ( $part_pkg->plan ) {
-
       $part_pkg->plan('flat');
+    }
 
-      if ( $part_pkg->setup =~ /^\s*([\d\.]+)\s*$/ ) {
+    if ( length($part_pkg->option('setup_fee')) == 0 
+         && $part_pkg->setup =~ /^\s*([\d\.]+)\s*$/ ) {
 
-        my $opt = new FS::part_pkg_option {
-          'pkgpart'     => $part_pkg->pkgpart,
-          'optionname'  => 'setup_fee',
-          'optionvalue' => $1,
-        };
-        my $error = $opt->insert;
-        die $error if $error;
+      my $opt = new FS::part_pkg_option {
+        'pkgpart'     => $part_pkg->pkgpart,
+        'optionname'  => 'setup_fee',
+        'optionvalue' => $1,
+      };
+      my $error = $opt->insert;
+      die $error if $error;
 
-        $part_pkg->setup('');
 
-      } else {
-        die "Can't parse part_pkg.setup for fee; convert pkgnum ".
-            $part_pkg->pkgnum. " manually: ". $part_pkg->setup. "\n";
-      }
+      #} else {
+      #  die "Can't parse part_pkg.setup for fee; convert pkgnum ".
+      #      $part_pkg->pkgnum. " manually: ". $part_pkg->setup. "\n";
+    }
+    $part_pkg->setup('');
 
-      if ( $part_pkg->recur =~ /^\s*([\d\.]+)\s*$/ ) {
+    if ( length($part_pkg->option('recur_fee')) == 0
+         && $part_pkg->recur =~ /^\s*([\d\.]+)\s*$/ ) {
 
         my $opt = new FS::part_pkg_option {
           'pkgpart'     => $part_pkg->pkgpart,
@@ -1255,14 +1296,12 @@ sub _upgrade_data { # class method
         my $error = $opt->insert;
         die $error if $error;
 
-        $part_pkg->recur('');
-
-      } else {
-        die "Can't parse part_pkg.setup for fee; convert pkgnum ".
-            $part_pkg->pkgnum. " manually: ". $part_pkg->setup. "\n";
-      }
 
+      #} else {
+      #  die "Can't parse part_pkg.setup for fee; convert pkgnum ".
+      #      $part_pkg->pkgnum. " manually: ". $part_pkg->setup. "\n";
     }
+    $part_pkg->recur('');
 
     $part_pkg->replace; #this should take care of plandata, right?
 
@@ -1281,6 +1320,7 @@ sub _upgrade_data { # class method
     $new->custom('Y');
     my $comment = $part_pkg->comment;
     $comment =~ s/^\(CUSTOM\) //;
+    $comment = '(none)' unless $comment =~ /\S/;
     $new->comment($comment);
 
     my $pkg_svc = { map { $_->svcpart => $_->quantity } $part_pkg->pkg_svc };