sansay CDRs, RT#5495
[freeside.git] / FS / FS / part_pkg.pm
index 8cfd614..ba80475 100644 (file)
@@ -85,6 +85,12 @@ inherits from FS::Record.  The following fields are currently supported:
 
 =item disabled - Disabled flag, empty or `Y'
 
+=item custom - Custom flag, empty or `Y'
+
+=item setup_cost - for cost tracking
+
+=item recur_cost - for cost tracking
+
 =item pay_weight - Weight (relative to credit_weight and other package definitions) that controls payment application to specific line items.
 
 =item credit_weight - Weight (relative to other package definitions) that controls credit application to specific line items.
@@ -109,9 +115,8 @@ sub table { 'part_pkg'; }
 =item clone
 
 An alternate constructor.  Creates a new package definition by duplicating
-an existing definition.  A new pkgpart is assigned and `(CUSTOM) ' is prepended
-to the comment field.  To add the package definition to the database, see
-L<"insert">.
+an existing definition.  A new pkgpart is assigned and the custom flag is
+set to Y.  To add the package definition to the database, see L<"insert">.
 
 =cut
 
@@ -120,8 +125,7 @@ sub clone {
   my $class = ref($self);
   my %hash = $self->hash;
   $hash{'pkgpart'} = '';
-  $hash{'comment'} = "(CUSTOM) ". $hash{'comment'}
-    unless $hash{'comment'} =~ /^\(CUSTOM\) /;
+  $hash{'custom'} = 'Y';
   #new FS::part_pkg ( \%hash ); # ?
   new $class ( \%hash ); # ?
 }
@@ -365,7 +369,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'
@@ -448,6 +452,11 @@ sub check {
     || $self->ut_enum('recurtax', [ '', 'Y' ] )
     || $self->ut_textn('taxclass')
     || $self->ut_enum('disabled', [ '', 'Y' ] )
+    || $self->ut_enum('custom', [ '', 'Y' ] )
+    #|| $self->ut_moneyn('setup_cost')
+    #|| $self->ut_moneyn('recur_cost')
+    || $self->ut_floatn('setup_cost')
+    || $self->ut_floatn('recur_cost')
     || $self->ut_floatn('pay_weight')
     || $self->ut_floatn('credit_weight')
     || $self->ut_numbern('taxproductnum')
@@ -480,20 +489,30 @@ sub check {
   '';
 }
 
-=item pkg_comment
+=item pkg_comment [ OPTION => VALUE... ]
 
 Returns an (internal) string representing this package.  Currently,
 "pkgpart: pkg - comment", is returned.  "pkg - comment" may be returned in the
-future, omitting pkgpart.
+future, omitting pkgpart.  The comment will have '(CUSTOM) ' prepended if
+custom is Y.
+
+If the option nopkgpart is true then the "pkgpart: ' is omitted.
 
 =cut
 
 sub pkg_comment {
   my $self = shift;
+  my %opt = @_;
 
   #$self->pkg. ' - '. $self->comment;
   #$self->pkg. ' ('. $self->comment. ')';
-  $self->pkgpart. ': '. $self->pkg. ' - '. $self->comment;
+  my $pre = $opt{nopkgpart} ? '' : $self->pkgpart. ': ';
+  $pre. $self->pkg. ' - '. $self->custom_comment;
+}
+
+sub custom_comment {
+  my $self = shift;
+  ( $self->custom ? '(CUSTOM) ' : '' ). $self->comment;
 }
 
 =item pkg_class
@@ -1206,27 +1225,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,
@@ -1236,19 +1257,45 @@ 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?
 
   }
 
+  # now upgrade to the explicit custom flag
+
+  @part_pkg = qsearch({
+    'table'     => 'part_pkg',
+    'hashref'   => { disabled => 'Y', custom => '' },
+    'extra_sql' => "AND comment LIKE '(CUSTOM) %'",
+  });
+
+  foreach my $part_pkg (@part_pkg) {
+    my $new = new FS::part_pkg { $part_pkg->hash };
+    $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 };
+    my $primary = $part_pkg->svcpart;
+    my $options = { $part_pkg->options };
+
+    my $error = $new->replace( $part_pkg,
+                               'pkg_svc'     => $pkg_svc,
+                               'primary_svc' => $primary,
+                               'options'     => $options,
+                             );
+    die $error if $error;
+  }
+
 }
 
 =item curuser_pkgs_sql
@@ -1371,6 +1418,8 @@ plandata should go
 
 part_pkg_taxrate is Pg specific
 
+replace should be smarter about managing the related tables (options, pkg_svc)
+
 =head1 SEE ALSO
 
 L<FS::Record>, L<FS::cust_pkg>, L<FS::type_pkgs>, L<FS::pkg_svc>, L<Safe>.