=item change
If set true, supresses actions that should only be taken for new package
-orders. (Currently this includes: intro periods when delay_setup is on.)
+orders. (Currently this includes: intro periods when delay_setup is on,
+auto-adding a 1st start date, auto-adding expiration/adjourn/contract_end dates)
=item options
my $part_pkg = $self->part_pkg;
- # if the package def says to start only on the first of the month:
- if ( $part_pkg->option('start_1st', 1) && !$self->start_date ) {
- my ($sec,$min,$hour,$mday,$mon,$year) = (localtime(time) )[0,1,2,3,4,5];
- $mon += 1 unless $mday == 1;
- until ( $mon < 12 ) { $mon -= 12; $year++; }
- $self->start_date( timelocal_nocheck(0,0,0,1,$mon,$year) );
- }
-
- # set up any automatic expire/adjourn/contract_end timers
- # based on the start date
- foreach my $action ( qw(expire adjourn contract_end) ) {
- my $months = $part_pkg->option("${action}_months",1);
- if($months and !$self->$action) {
- my $start = $self->start_date || $self->setup || time;
- $self->$action( $part_pkg->add_freq($start, $months) );
+ if ( ! $options{'change'} ) {
+
+ # if the package def says to start only on the first of the month:
+ if ( $part_pkg->option('start_1st', 1) && !$self->start_date ) {
+ my ($sec,$min,$hour,$mday,$mon,$year) = (localtime(time) )[0,1,2,3,4,5];
+ $mon += 1 unless $mday == 1;
+ until ( $mon < 12 ) { $mon -= 12; $year++; }
+ $self->start_date( timelocal_nocheck(0,0,0,1,$mon,$year) );
+ }
+
+ # set up any automatic expire/adjourn/contract_end timers
+ # based on the start date
+ foreach my $action ( qw(expire adjourn contract_end) ) {
+ my $months = $part_pkg->option("${action}_months",1);
+ if($months and !$self->$action) {
+ my $start = $self->start_date || $self->setup || time;
+ $self->$action( $part_pkg->add_freq($start, $months) );
+ }
+ }
+
+ # 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 ( ! $options{'change'}
+ && $part_pkg->option('free_days',1)
+ && $part_pkg->option('delay_setup',1)
+ #&& ! $self->start_date
+ )
+ {
+ $self->start_date( $part_pkg->default_start_date );
}
- }
- # if this package has "free days" and delayed setup fee, tehn
- # set start date that many days in the future.
- # (this should have been set in the UI, but enforce it here)
- if ( ! $options{'change'}
- && ( my $free_days = $part_pkg->option('free_days',1) )
- && $part_pkg->option('delay_setup',1)
- #&& ! $self->start_date
- )
- {
- $self->start_date( $part_pkg->default_start_date );
}
- $self->order_date(time);
+ # set order date unless this was previously a different package
+ $self->order_date(time) unless $self->change_pkgnum;
local $SIG{HUP} = 'IGNORE';
local $SIG{INT} = 'IGNORE';
'to' => \@invoicing_list,
'subject' => ( $conf->config('cancelsubject') || 'Cancellation Notice' ),
'body' => [ map "$_\n", $conf->config('cancelmessage') ],
+ 'custnum' => $self->custnum,
+ 'msgtype' => '', #admin?
);
}
#should this do something on errors?
'Package : #'. $self->pkgnum. " (". $self->part_pkg->pkg_comment. ")\n",
( map { "Service : $_\n" } @labels ),
],
+ 'custnum' => $self->custnum,
+ 'msgtype' => 'admin'
);
if ( $error ) {
: ''
),
],
+ 'custnum' => $self->custnum,
+ 'msgtype' => 'admin',
);
if ( $error ) {
$error = $opt->{'cust_location'}->find_or_insert;
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
- return "inserting cust_location (transaction rolled back): $error";
+ return "creating location record: $error";
}
$opt->{'locationnum'} = $opt->{'cust_location'}->locationnum;
}
$hash{$date} = $self->getfield($date);
}
}
+ # always keep this date, regardless of anything
+ # (the date of the package change is in a different field)
+ $hash{'order_date'} = $self->getfield('order_date');
# allow $opt->{'locationnum'} = '' to specifically set it to null
# (i.e. customer default location)
my $error = $cust_main->insert( @{ $opt->{cust_main_insert_args}||[] } );
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
- return "inserting cust_main (transaction rolled back): $error";
+ return "inserting customer record: $error";
}
}
$custnum = $cust_main->custnum;
}
if ($error) {
$dbh->rollback if $oldAutoCommit;
- return $error;
+ return "inserting new package: $error";
}
# Transfer services and cancel old package.
if ($error and $error == 0) {
# $old_pkg->transfer failed.
$dbh->rollback if $oldAutoCommit;
- return $error;
+ return "transferring $error";
}
if ( $error > 0 && $conf->exists('cust_pkg-change_svcpart') ) {
if ($error and $error == 0) {
# $old_pkg->transfer failed.
$dbh->rollback if $oldAutoCommit;
- return $error;
+ return "converting $error";
}
}
# Transfers were successful, but we still had services left on the old
# package. We can't change the package under this circumstances, so abort.
$dbh->rollback if $oldAutoCommit;
- return "Unable to transfer all services from package ". $self->pkgnum;
+ return "unable to transfer all services";
}
#reset usage if changing pkgpart
if ($error) {
$dbh->rollback if $oldAutoCommit;
- return "Error setting usage values: $error";
+ return "setting usage values: $error";
}
} else {
# if NOT changing pkgpart, transfer any usage pools over
$error = $usage->replace;
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
- return "Error transferring usage pools: $error";
+ return "transferring usage pools: $error";
}
}
}
$error = $new_discount->insert;
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
- return "Error transferring discounts: $error";
+ return "transferring discounts: $error";
}
}
}
$error = $new_detail->insert;
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
- return "Error transferring package notes: $error";
+ return "transferring package notes: $error";
}
}
);
if ($error) {
$dbh->rollback if $oldAutoCommit;
- return $error;
+ return "canceling old package: $error";
}
if ( $conf->exists('cust_pkg-change_pkgpart-bill_now') ) {
);
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
- return $error;
+ return "billing new package: $error";
}
}
}
}
+ my $error;
foreach my $cust_svc ($self->cust_svc) {
+ my $svcnum = $cust_svc->svcnum;
if($target{$cust_svc->svcpart} > 0
or $FS::cust_svc::ignore_quantity) { # maybe should be a 'force' option
$target{$cust_svc->svcpart}--;
my $new = new FS::cust_svc { $cust_svc->hash };
$new->pkgnum($dest_pkgnum);
- my $error = $new->replace($cust_svc);
- return $error if $error;
+ $error = $new->replace($cust_svc);
} elsif ( exists $opt{'change_svcpart'} && $opt{'change_svcpart'} ) {
if ( $DEBUG ) {
warn "looking for alternates for svcpart ". $cust_svc->svcpart. "\n";
my $new = new FS::cust_svc { $cust_svc->hash };
$new->svcpart($change_svcpart);
$new->pkgnum($dest_pkgnum);
- my $error = $new->replace($cust_svc);
- return $error if $error;
+ $error = $new->replace($cust_svc);
} else {
$remaining++;
}
} else {
$remaining++
}
+ if ( $error ) {
+ my @label = $cust_svc->label;
+ return "service $label[1]: $error";
+ }
}
return $remaining;
}
);
if( exists($params->{'active'} ) ) {
- # This overrides all the other date-related fields
+ # This overrides all the other date-related fields, and includes packages
+ # that were active at some time during the interval. It excludes:
+ # - packages that were set up after the end of the interval
+ # - packages that were canceled before the start of the interval
+ # - packages that were suspended before the start of the interval
+ # and are still suspended now
my($beginning, $ending) = @{$params->{'active'}};
push @where,
"cust_pkg.setup IS NOT NULL",
"cust_pkg.setup <= $ending",
"(cust_pkg.cancel IS NULL OR cust_pkg.cancel >= $beginning )",
+ "(cust_pkg.susp IS NULL OR cust_pkg.susp >= $beginning )",
"NOT (".FS::cust_pkg->onetime_sql . ")";
}
else {