=head1 SYNOPSIS
-=head1 DESRIPTION
+=head1 DESCRIPTION
These methods are available on FS::cust_main objects;
Orders a single package.
+Note that if the package definition has supplemental packages, those will
+be ordered as well.
+
Options may be passed as a list of key/value pairs or as a hash reference.
Options are:
=item cust_location
-Optional FS::cust_location object
+Optional FS::cust_location object. If not specified, the customer's
+ship_location will be used.
=item svcs
Optional subject for a ticket created and attached to this customer
-=item ticket_subject
+=item ticket_queue
Optional queue name for ticket additions
my $self = shift;
my $opt = ref($_[0]) ? shift : { @_ };
+ local($DEBUG) = $FS::cust_main::DEBUG if $FS::cust_main::DEBUG > $DEBUG;
+
warn "$me order_pkg called with options ".
join(', ', map { "$_: $opt->{$_}" } keys %$opt ). "\n"
if $DEBUG;
}
$cust_pkg->locationnum($opt->{'cust_location'}->locationnum);
}
+ else {
+ $cust_pkg->locationnum($self->ship_locationnum);
+ }
$cust_pkg->custnum( $self->custnum );
}
}
+ # add supplemental packages, if any are needed
+ my $part_pkg = FS::part_pkg->by_key($cust_pkg->pkgpart);
+ foreach my $link ($part_pkg->supp_part_pkg_link) {
+ #warn "inserting supplemental package ".$link->dst_pkgpart;
+ my $pkg = FS::cust_pkg->new({
+ 'pkgpart' => $link->dst_pkgpart,
+ 'pkglinknum' => $link->pkglinknum,
+ 'custnum' => $self->custnum,
+ 'main_pkgnum' => $cust_pkg->pkgnum,
+ 'locationnum' => $cust_pkg->locationnum,
+ # try to prevent as many surprises as possible
+ 'pkgbatch' => $cust_pkg->pkgbatch,
+ 'start_date' => $cust_pkg->start_date,
+ 'order_date' => $cust_pkg->order_date,
+ 'expire' => $cust_pkg->expire,
+ 'adjourn' => $cust_pkg->adjourn,
+ 'contract_end' => $cust_pkg->contract_end,
+ 'refnum' => $cust_pkg->refnum,
+ 'discountnum' => $cust_pkg->discountnum,
+ 'waive_setup' => $cust_pkg->waive_setup,
+ });
+ $error = $self->order_pkg('cust_pkg' => $pkg);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "inserting supplemental package: $error";
+ }
+ }
+
$dbh->commit or die $dbh->errstr if $oldAutoCommit;
''; #no error
}
-#deprecated #=item order_pkgs HASHREF [ , SECONDSREF ] [ , OPTION => VALUE ... ]
=item order_pkgs HASHREF [ , OPTION => VALUE ... ]
Like the insert method on an existing record, this method orders multiple
sub order_pkgs {
my $self = shift;
my $cust_pkgs = shift;
- my $seconds_ref = ref($_[0]) ? shift : ''; #deprecated
my %options = @_;
- $seconds_ref ||= $options{'seconds_ref'};
+
+ local($DEBUG) = $FS::cust_main::DEBUG if $FS::cust_main::DEBUG > $DEBUG;
warn "$me order_pkgs called with options ".
join(', ', map { "$_: $options{$_}" } keys %options ). "\n"
my $error = $self->order_pkg(
'cust_pkg' => $cust_pkg,
'svcs' => $cust_pkgs->{$cust_pkg},
- 'seconds_ref' => $seconds_ref,
- map { $_ => $options{$_} } qw( upbytes_ref downbytes_ref totalbytes_ref
- depend_jobnum
- )
+ map { $_ => $options{$_} }
+ qw( seconds_ref upbytes_ref downbytes_ref totalbytes_ref depend_jobnum )
);
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
my $self = shift;
my $extra_qsearch = ref($_[0]) ? shift : {};
+ local($DEBUG) = $FS::cust_main::DEBUG if $FS::cust_main::DEBUG > $DEBUG;
+
return $self->num_ncancelled_pkgs unless wantarray;
my @cust_pkg = ();
sub suspended_pkgs {
my $self = shift;
+ return $self->num_suspended_pkgs unless wantarray;
grep { $_->susp } $self->ncancelled_pkgs;
}
sub unsuspended_pkgs {
my $self = shift;
+ return $self->num_unsuspended_pkgs unless wantarray;
grep { ! $_->susp } $self->ncancelled_pkgs;
}
+=item active_pkgs
+
+Returns all unsuspended (and uncancelled) packages (see L<FS::cust_pkg>) for
+this customer that are active (recurring).
+
+=cut
+
+sub active_pkgs {
+ my $self = shift;
+ grep { my $part_pkg = $_->part_pkg;
+ $part_pkg->freq ne '' && $part_pkg->freq ne '0';
+ }
+ $self->unsuspended_pkgs;
+}
+
+=item billing_pkgs
+
+Returns active packages, and also any suspended packages which are set to
+continue billing while suspended.
+
+=cut
+
+sub billing_pkgs {
+ my $self = shift;
+ grep { my $part_pkg = $_->part_pkg;
+ $part_pkg->freq ne '' && $part_pkg->freq ne '0'
+ && ( ! $_->susp || $_->option('suspend_bill',1)
+ || ( $part_pkg->option('suspend_bill', 1)
+ && ! $_->option('no_suspend_bill',1)
+ )
+ );
+ }
+ $self->ncancelled_pkgs;
+}
+
=item next_bill_date
Returns the next date this customer will be billed, as a UNIX timestamp, or
-undef if no active package has a next bill date.
+undef if no billing package has a next bill date.
=cut
sub next_bill_date {
my $self = shift;
- min( map $_->get('bill'), grep $_->get('bill'), $self->unsuspended_pkgs );
+ min( map $_->get('bill'), grep $_->get('bill'), $self->billing_pkgs );
}
=item num_cancelled_pkgs
shift->num_pkgs("( cust_pkg.cancel IS NULL OR cust_pkg.cancel = 0 )");
}
+sub num_suspended_pkgs {
+ shift->num_pkgs(" ( cust_pkg.cancel IS NULL OR cust_pkg.cancel = 0 )
+ AND cust_pkg.susp IS NOT NULL AND cust_pkg.susp != 0 ");
+}
+
+sub num_unsuspended_pkgs {
+ shift->num_pkgs(" ( cust_pkg.cancel IS NULL OR cust_pkg.cancel = 0 )
+ AND ( cust_pkg.susp IS NULL OR cust_pkg.susp = 0 ) ");
+}
+
sub num_pkgs {
my( $self ) = shift;
my $sql = scalar(@_) ? shift : '';