+=item set_initial_timers
+
+If required by the package definition, sets any automatic expire, adjourn,
+or contract_end timers to some number of months after the start date
+(or setup date, if the package has already been setup). If the package has
+a delayed setup fee after a period of "free days", will also set the
+start date to the end of that period.
+
+If the package has an automatic transfer rule (C<change_to_pkgnum>), then
+this will also order the package and set its start date.
+
+=cut
+
+sub set_initial_timers {
+ my $self = shift;
+ my $part_pkg = $self->part_pkg;
+ my $start = $self->start_date || $self->setup || time;
+
+ foreach my $action ( qw(expire adjourn contract_end) ) {
+ my $months = $part_pkg->get("${action}_months");
+ if($months and !$self->get($action)) {
+ $self->set($action, $part_pkg->add_freq($start, $months) );
+ }
+ }
+
+ # if this package has an expire date and a change_to_pkgpart, set automatic
+ # package transfer
+ # (but don't call change_later, as that would call $self->replace, and we're
+ # probably in the middle of $self->insert right now)
+ if ( $part_pkg->expire_months and $part_pkg->change_to_pkgpart ) {
+ if ( $self->change_to_pkgnum ) {
+ # this can happen if a package is ordered on hold, scheduled for a
+ # future change _while on hold_, and then released from hold, causing
+ # the automatic transfer to schedule.
+ #
+ # what's correct behavior in that case? I think it's to disallow
+ # future-changing an on-hold package that has an automatic transfer.
+ # but if we DO get into this situation, let the manual package change
+ # win.
+ warn "pkgnum ".$self->pkgnum.": manual future package change blocks ".
+ "automatic transfer.\n";
+ } else {
+ my $change_to = FS::cust_pkg->new( {
+ start_date => $self->get('expire'),
+ pkgpart => $part_pkg->change_to_pkgpart,
+ map { $_ => $self->get($_) }
+ qw( custnum locationnum quantity refnum salesnum contract_end )
+ } );
+ my $error = $change_to->insert;
+
+ return $error if $error;
+ $self->set('change_to_pkgnum', $change_to->pkgnum);
+ }
+ }
+
+ # if this package has "free days" and delayed setup fee, then
+ # set start date that many days in the future.
+ # (this should have been set in the UI, but enforce it here)
+ if ( $part_pkg->option('free_days',1)
+ && $part_pkg->option('delay_setup',1)
+ )
+ {
+ $self->start_date( $part_pkg->default_start_date );
+ }
+
+ '';
+}
+