Merge branch 'master' of git.freeside.biz:/home/git/freeside
[freeside.git] / FS / FS / part_pkg.pm
index 2fba2f4..498da8a 100644 (file)
@@ -30,6 +30,7 @@ use FS::part_pkg_link;
 use FS::part_pkg_discount;
 use FS::part_pkg_vendor;
 use FS::part_pkg_currency;
+use FS::part_svc_link;
 
 $DEBUG = 0;
 $setup_hack = 0;
@@ -126,6 +127,18 @@ part_pkg, will be equal to pkgpart.
 ordered. The package will not start billing or have a setup fee charged 
 until it is manually unsuspended.
 
+=item change_to_pkgpart - When this package is ordered, schedule a future 
+package change. The 'expire_months' field will determine when the package
+change occurs.
+
+=item expire_months - Number of months until this package expires (or changes
+to another package).
+
+=item adjourn_months - Number of months until this package becomes suspended.
+
+=item contract_end_months - Number of months until the package's contract 
+ends.
+
 =back
 
 =head1 METHODS
@@ -721,6 +734,11 @@ sub check {
     || $self->ut_numbern('delay_start')
     || $self->ut_foreign_keyn('successor', 'part_pkg', 'pkgpart')
     || $self->ut_foreign_keyn('family_pkgpart', 'part_pkg', 'pkgpart')
+    || $self->ut_numbern('expire_months')
+    || $self->ut_numbern('adjourn_months')
+    || $self->ut_numbern('contract_end_months')
+    || $self->ut_numbern('change_to_pkgpart')
+    || $self->ut_foreign_keyn('change_to_pkgpart', 'part_pkg', 'pkgpart')
     || $self->ut_alphan('agent_pkgpartid')
     || $self->SUPER::check
   ;
@@ -753,17 +771,12 @@ sub check_pkg_svc {
 
   foreach my $svcpart ( keys %pkg_svc ) {
 
-    warn 'checking '. $pkg_svc{$svcpart}->svcpart;
-
     foreach my $part_svc_link ( $self->part_svc_link(
                                   'src_svcpart' => $svcpart,
                                   'link_type'   => 'part_pkg_restrict',
                                 )
     ) {
 
-      use Data::Dumper;
-      warn 'checking '. Dumper($part_svc_link);
-
       return $part_svc_link->dst_svc. ' must be included with '.
              $part_svc_link->src_svc
         unless $pkg_svc{ $part_svc_link->dst_svcpart };
@@ -801,17 +814,7 @@ src_svcpart and link_type.
 =cut
 
 sub part_svc_link {
-  my( $self, %opt ) = @_;
-
-  my $agentnum = $self->agentnum;
-
-  qsearch({ 'table'     => 'part_svc_link',
-            'hashref'   => \%opt,
-            'extra_sql' =>
-              $agentnum
-                ? "AND ( agentnum IS NULL OR agentnum = $agentnum )"
-                : 'AND agentnum IS NULL',
-         });
+  FS::part_svc_link->by_agentnum( shift->agentnum, @_ );
 }
 
 =item supersede OLD [, OPTION => VALUE ... ]
@@ -1406,6 +1409,11 @@ sub option {
   my %plandata = map { /^(\w+)=(.*)$/; ( $1 => $2 ); }
                      split("\n", $self->get('plandata') );
   return $plandata{$opt} if exists $plandata{$opt};
+
+  # check whether the option is defined in plan info (if so, don't warn)
+  if (exists $plans{ $self->plan }->{fields}->{$opt}) {
+    return '';
+  }
   cluck "WARNING: (pkgpart ". $self->pkgpart. ") Package def option $opt ".
         "not found in options or plandata!\n"
     unless $ornull;
@@ -1705,6 +1713,19 @@ for this package.
 Returns the voice usage pools (see L<FS::part_pkg_usage>) defined for 
 this package.
 
+=item change_to_pkg
+
+Returns the automatic transfer target for this package, or an empty string
+if there isn't one.
+
+=cut
+
+sub change_to_pkg {
+  my $self = shift;
+  my $pkgpart = $self->change_to_pkgpart or return '';
+  FS::part_pkg->by_key($pkgpart);
+}
+
 =item _rebless
 
 Reblesses the object into the FS::part_pkg::PLAN class (if available), where
@@ -2211,6 +2232,19 @@ sub queueable_upgrade {
     FS::upgrade_journal->set_done($upgrade);
   }
 
+  # migrate adjourn_months, expire_months, and contract_end_months to 
+  # real fields
+  foreach my $field (qw(adjourn_months expire_months contract_end_months)) {
+    foreach my $option (qsearch('part_pkg_option', { optionname => $field })) {
+      my $part_pkg = $option->part_pkg;
+      my $error = $option->delete;
+      if ( $option->optionvalue and $part_pkg->get($field) eq '' ) {
+        $part_pkg->set($field, $option->optionvalue);
+        $error ||= $part_pkg->replace;
+      }
+      die $error if $error;
+    }
+  }
 }
 
 =item curuser_pkgs_sql