summaryrefslogtreecommitdiff
path: root/FS/FS/cust_main.pm
diff options
context:
space:
mode:
Diffstat (limited to 'FS/FS/cust_main.pm')
-rw-r--r--FS/FS/cust_main.pm117
1 files changed, 96 insertions, 21 deletions
diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm
index 417937a..011308c 100644
--- a/FS/FS/cust_main.pm
+++ b/FS/FS/cust_main.pm
@@ -1,7 +1,7 @@
package FS::cust_main;
use strict;
-use vars qw( @ISA $conf $Debug $import );
+use vars qw( @ISA $conf $DEBUG $import );
use Safe;
use Carp;
BEGIN {
@@ -38,8 +38,8 @@ use FS::Msgcat qw(gettext);
@ISA = qw( FS::Record );
-$Debug = 0;
-#$Debug = 1;
+$DEBUG = 0;
+#$DEBUG = 1;
$import = 0;
@@ -223,10 +223,16 @@ invoicing_list destination to the newly-created svc_acct. Here's an example:
$cust_main->insert( {}, [ $email, 'POST' ] );
-Currently available options are: I<noexport>
+Currently available options are: I<depend_jobnum> and I<noexport>.
-If I<noexport> is set true, no provisioning jobs (exports) are scheduled.
-(You can schedule them later with the B<reexport> method.)
+If I<depend_jobnum> is set, all provisioning jobs will have a dependancy
+on the supplied jobnum (they will not run until the specific job completes).
+This can be used to defer provisioning until some action completes (such
+as running the customer's credit card sucessfully).
+
+The I<noexport> option is deprecated. If I<noexport> is set true, no
+provisioning jobs (exports) are scheduled. (You can schedule them later with
+the B<reexport> method.)
=cut
@@ -235,6 +241,9 @@ sub insert {
my $cust_pkgs = @_ ? shift : {};
my $invoicing_list = @_ ? shift : '';
my %options = @_;
+ warn "FS::cust_main::insert called with options ".
+ join(', ', map { "$_: $options{$_}" } keys %options ). "\n"
+ if $DEBUG;
local $SIG{HUP} = 'IGNORE';
local $SIG{INT} = 'IGNORE';
@@ -286,7 +295,6 @@ sub insert {
}
# packages
- #local $FS::svc_Common::noexport_hack = 1 if $options{'noexport'};
$error = $self->order_pkgs($cust_pkgs, \$seconds, %options);
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
@@ -321,7 +329,7 @@ sub insert {
}
-=item order_pkgs HASHREF, [ , OPTION => VALUE ... ] ]
+=item order_pkgs HASHREF, [ SECONDSREF, [ , OPTION => VALUE ... ] ]
Like the insert method on an existing record, this method orders a package
and included services atomicaly. Pass a Tie::RefHash data structure to this
@@ -334,14 +342,20 @@ be a better explanation of this, but until then, here's an example:
$cust_pkg => [ $svc_acct ],
...
);
- $cust_main->order_pkgs( \%hash, 'noexport'=>1 );
+ $cust_main->order_pkgs( \%hash, \'0', 'noexport'=>1 );
+
+Currently available options are: I<depend_jobnum> and I<noexport>.
-Currently available options are: I<noexport>
+If I<depend_jobnum> is set, all provisioning jobs will have a dependancy
+on the supplied jobnum (they will not run until the specific job completes).
+This can be used to defer provisioning until some action completes (such
+as running the customer's credit card sucessfully).
-If I<noexport> is set true, no provisioning jobs (exports) are scheduled.
-(You can schedule them later with the B<reexport> method for each
-cust_pkg object. Using the B<reexport> method on the cust_main object is not
-recommended, as existing services will also be reexported.)
+The I<noexport> option is deprecated. If I<noexport> is set true, no
+provisioning jobs (exports) are scheduled. (You can schedule them later with
+the B<reexport> method for each cust_pkg object. Using the B<reexport> method
+on the cust_main object is not recommended, as existing services will also be
+reexported.)
=cut
@@ -350,6 +364,12 @@ sub order_pkgs {
my $cust_pkgs = shift;
my $seconds = shift;
my %options = @_;
+ my %svc_options = ();
+ $svc_options{'depend_jobnum'} = $options{'depend_jobnum'}
+ if exists $options{'depend_jobnum'};
+ warn "FS::cust_main::order_pkgs called with options ".
+ join(', ', map { "$_: $options{$_}" } keys %options ). "\n"
+ if $DEBUG;
local $SIG{HUP} = 'IGNORE';
local $SIG{INT} = 'IGNORE';
@@ -377,7 +397,7 @@ sub order_pkgs {
$svc_something->seconds( $svc_something->seconds + $$seconds );
$$seconds = 0;
}
- $error = $svc_something->insert;
+ $error = $svc_something->insert(%svc_options);
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
#return "inserting svc_ (transaction rolled back): $error";
@@ -392,6 +412,9 @@ sub order_pkgs {
=item reexport
+This method is deprecated. See the I<depend_jobnum> option to the insert and
+order_pkgs methods for a better way to defer provisioning.
+
Re-schedules all exports by calling the B<reexport> method of all associated
packages (see L<FS::cust_pkg>). If there is an error, returns the error;
otherwise returns false.
@@ -401,6 +424,9 @@ otherwise returns false.
sub reexport {
my $self = shift;
+ carp "warning: FS::cust_main::reexport is deprectated; ".
+ "use the depend_jobnum option to insert or order_pkgs to delay export";
+
local $SIG{HUP} = 'IGNORE';
local $SIG{INT} = 'IGNORE';
local $SIG{QUIT} = 'IGNORE';
@@ -986,6 +1012,38 @@ sub suspend {
grep { $_->suspend } $self->unsuspended_pkgs;
}
+=item suspend_if_pkgpart PKGPART [ , PKGPART ... ]
+
+Suspends all unsuspended packages (see L<FS::cust_pkg>) matching the listed
+PKGPARTs (see L<FS::part_pkg>). Always returns a list: an empty list on
+success or a list of errors.
+
+=cut
+
+sub suspend_if_pkgpart {
+ my $self = shift;
+ my @pkgparts = @_;
+ grep { $_->suspend }
+ grep { my $pkgpart = $_->pkgpart; grep { $pkgpart eq $_ } @pkgparts }
+ $self->unsuspended_pkgs;
+}
+
+=item suspend_unless_pkgpart PKGPART [ , PKGPART ... ]
+
+Suspends all unsuspended packages (see L<FS::cust_pkg>) unless they match the
+listed PKGPARTs (see L<FS::part_pkg>). Always returns a list: an empty list
+on success or a list of errors.
+
+=cut
+
+sub suspend_unless_pkgpart {
+ my $self = shift;
+ my @pkgparts = @_;
+ grep { $_->suspend }
+ grep { my $pkgpart = $_->pkgpart; ! grep { $pkgpart eq $_ } @pkgparts }
+ $self->unsuspended_pkgs;
+}
+
=item cancel [ OPTION => VALUE ... ]
Cancels all uncancelled packages (see L<FS::cust_pkg>) for this customer.
@@ -1000,7 +1058,7 @@ Always returns a list: an empty list on success or a list of errors.
sub cancel {
my $self = shift;
- grep { $_->cancel(@_) } $self->ncancelled_pkgs;
+ grep { $_ } map { $_->cancel(@_) } $self->ncancelled_pkgs;
}
=item agent
@@ -1040,6 +1098,7 @@ If there is an error, returns the error, otherwise returns false.
sub bill {
my( $self, %options ) = @_;
+ return '' if $self->payby eq 'COMP';
my $time = $options{'time'} || time;
my $error;
@@ -1056,6 +1115,8 @@ sub bill {
local $FS::UID::AutoCommit = 0;
my $dbh = dbh;
+ $self->select_for_update; #mutex
+
# find the packages which are due for billing, find out how much they are
# & generate invoice database.
@@ -1453,8 +1514,10 @@ sub collect {
local $FS::UID::AutoCommit = 0;
my $dbh = dbh;
+ $self->select_for_update; #mutex
+
my $balance = $self->balance;
- warn "collect customer". $self->custnum. ": balance $balance" if $Debug;
+ warn "collect customer". $self->custnum. ": balance $balance" if $DEBUG;
unless ( $balance > 0 ) { #redundant?????
$dbh->rollback if $oldAutoCommit; #hmm
return '';
@@ -1480,14 +1543,14 @@ sub collect {
last if $self->balance <= 0;
warn "invnum ". $cust_bill->invnum. " (owed ". $cust_bill->owed. ")"
- if $Debug;
+ if $DEBUG;
foreach my $part_bill_event (
sort { $a->seconds <=> $b->seconds
|| $a->weight <=> $b->weight
|| $a->eventpart <=> $b->eventpart }
grep { $_->seconds <= ( $invoice_time - $cust_bill->_date )
- && ! qsearchs( 'cust_bill_event', {
+ && ! qsearch( 'cust_bill_event', {
'invnum' => $cust_bill->invnum,
'eventpart' => $_->eventpart,
'status' => 'done',
@@ -1501,7 +1564,7 @@ sub collect {
|| $self->balance <= 0; # or if balance<=0
warn "calling invoice event (". $part_bill_event->eventcode. ")\n"
- if $Debug;
+ if $DEBUG;
my $cust_main = $self; #for callback
my $error;
@@ -2146,6 +2209,18 @@ sub cust_refund {
qsearch( 'cust_refund', { 'custnum' => $self->custnum } )
}
+=item select_for_update
+
+Selects this record with the SQL "FOR UPDATE" command. This can be useful as
+a mutex.
+
+=cut
+
+sub select_for_update {
+ my $self = shift;
+ qsearch('cust_main', { 'custnum' => $self->custnum }, '*', 'FOR UPDATE' );
+}
+
=back
=head1 SUBROUTINES
@@ -2336,7 +2411,7 @@ sub batch_import {
my %cust_main = (
agentnum => $agentnum,
refnum => $refnum,
- country => 'US', #default
+ country => $conf->config('countrydefault') || 'US',
payby => 'BILL', #default
paydate => '12/2037', #default
);