}
use Digest::MD5 qw(md5_base64);
use Date::Format;
+use Date::Parse;
#use Date::Manip;
use String::Approx qw(amatch);
use Business::CreditCard 0.28;
=item referral_custnum - referring customer number
+=item spool_cdr - Enable individual CDR spooling, empty or `Y'
+
=back
=head1 METHODS
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).
+as running the customer's credit card successfully).
The I<noexport> option is deprecated. If I<noexport> is set true, no
provisioning jobs (exports) are scheduled. (You can schedule them later with
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).
+as running the customer's credit card successfully).
The I<noexport> option is deprecated. If I<noexport> is set true, no
provisioning jobs (exports) are scheduled. (You can schedule them later with
my $self = shift;
my $old = shift;
my @param = @_;
+ warn "$me replace called\n"
+ if $DEBUG;
local $SIG{HUP} = 'IGNORE';
local $SIG{INT} = 'IGNORE';
my $payinfo = $self->payinfo;
$payinfo =~ s/[^\d\@]//g;
- $payinfo =~ /^(\d+)\@(\d{9})$/ or return 'invalid echeck account@aba';
- $payinfo = "$1\@$2";
+ if ( $conf->exists('echeck-nonus') ) {
+ $payinfo =~ /^(\d+)\@(\d+)$/ or return 'invalid echeck account@aba';
+ $payinfo = "$1\@$2";
+ } else {
+ $payinfo =~ /^(\d+)\@(\d{9})$/ or return 'invalid echeck account@aba';
+ $payinfo = "$1\@$2";
+ }
$self->payinfo($payinfo);
$self->paycvv('') if $self->dbdef_table->column('paycvv');
}
if ( $self->paydate eq '' || $self->paydate eq '-' ) {
- return "Expriation date required"
+ return "Expiration date required"
unless $self->payby =~ /^(BILL|PREPAY|CHEK|DCHK|LECB|CASH|WEST|MCRD)$/;
$self->paydate('');
} else {
$self->payname($1);
}
- $self->tax =~ /^(Y?)$/ or return "Illegal tax: ". $self->tax;
- $self->tax($1);
+ foreach my $flag (qw( tax spool_cdr )) {
+ $self->$flag() =~ /^(Y?)$/ or return "Illegal $flag: ". $self->$flag();
+ $self->$flag($1);
+ }
$self->otaker(getotaker) unless $self->otaker;
my( $total_setup, $total_recur ) = ( 0, 0 );
my %tax;
+ my @precommit_hooks = ();
foreach my $cust_pkg (
qsearch('cust_pkg', { 'custnum' => $self->custnum } )
$setup = eval { $cust_pkg->calc_setup( $time ) };
if ( $@ ) {
$dbh->rollback if $oldAutoCommit;
- return $@;
+ return "$@ running calc_setup for $cust_pkg\n";
}
$cust_pkg->setfield('setup', $time) unless $cust_pkg->setup;
# XXX shared with $recur_prog
$sdate = $cust_pkg->bill || $cust_pkg->setup || $time;
- $recur = eval { $cust_pkg->calc_recur( \$sdate, \@details ) };
+ #over two params! lets at least switch to a hashref for the rest...
+ my %param = ( 'precommit_hooks' => \@precommit_hooks, );
+
+ $recur = eval { $cust_pkg->calc_recur( \$sdate, \@details, \%param ) };
if ( $@ ) {
$dbh->rollback if $oldAutoCommit;
- return $@;
+ return "$@ running calc_recur for $cust_pkg\n";
}
#change this bit to use Date::Manip? CAREFUL with timezones (see
unless ( $self->tax =~ /Y/i || $self->payby eq 'COMP' ) {
- my @taxes = qsearch( 'cust_main_county', {
- 'state' => $self->state,
- 'county' => $self->county,
- 'country' => $self->country,
- 'taxclass' => $part_pkg->taxclass,
- } );
+ my $prefix =
+ ( $conf->exists('tax-ship_address') && length($self->ship_last) )
+ ? 'ship_'
+ : '';
+ my %taxhash = map { $_ => $self->get("$prefix$_") }
+ qw( state county country );
+
+ $taxhash{'taxclass'} = $part_pkg->taxclass;
+
+ my @taxes = qsearch( 'cust_main_county', \%taxhash );
+
unless ( @taxes ) {
- @taxes = qsearch( 'cust_main_county', {
- 'state' => $self->state,
- 'county' => $self->county,
- 'country' => $self->country,
- 'taxclass' => '',
- } );
+ $taxhash{'taxclass'} = '';
+ @taxes = qsearch( 'cust_main_county', \%taxhash );
}
#one more try at a whole-country tax rate
unless ( @taxes ) {
- @taxes = qsearch( 'cust_main_county', {
- 'state' => '',
- 'county' => '',
- 'country' => $self->country,
- 'taxclass' => '',
- } );
+ $taxhash{$_} = '' foreach qw( state county );
+ @taxes = qsearch( 'cust_main_county', \%taxhash );
}
# maybe eliminate this entirely, along with all the 0% records
$dbh->rollback if $oldAutoCommit;
return
"fatal: can't find tax rate for state/county/country/taxclass ".
- join('/', ( map $self->$_(), qw(state county country) ),
- $part_pkg->taxclass ). "\n";
+ join('/', ( map $self->get("$prefix$_"),
+ qw(state county country)
+ ),
+ $part_pkg->taxclass ). "\n";
}
foreach my $tax ( @taxes ) {
$dbh->rollback if $oldAutoCommit;
return "can't update charged for invoice #$invnum: $error";
}
+
+ foreach my $hook ( @precommit_hooks ) {
+ eval {
+ &{$hook}; #($self) ?
+ };
+ if ( $@ ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "$@ running precommit hook $hook\n";
+ }
+ }
$dbh->commit or die $dbh->errstr if $oldAutoCommit;
''; #no error
I<description> is a free-text field passed to the gateway. It defaults to
"Internet services".
-If an I<invnum> is specified, this payment (if sucessful) is applied to the
+If an I<invnum> is specified, this payment (if successful) is applied to the
specified invoice. If you don't specify an I<invnum> you might want to
call the B<apply_payments> method.
$capture->submit();
unless ( $capture->is_success ) {
- my $e = "Authorization sucessful but capture failed, custnum #".
+ my $e = "Authorization successful but capture failed, custnum #".
$self->custnum. ': '. $capture->result_code.
": ". $capture->error_message;
warn $e;
#I<zip>, I<payinfo> and I<paydate> are also available. Any of these options,
#if set, will override the value from the customer record.
-#If an I<invnum> is specified, this payment (if sucessful) is applied to the
+#If an I<invnum> is specified, this payment (if successful) is applied to the
#specified invoice. If you don't specify an I<invnum> you might want to
#call the B<apply_payments> method.
)
"; }
+=item uncancel_sql
+=item uncancelled_sql
+
+Returns an SQL expression identifying un-cancelled cust_main records.
+
+=cut
+
+sub uncancelled_sql { uncancel_sql(@_); }
+sub uncancel_sql { "
+ ( 0 < ( SELECT COUNT(*) FROM cust_pkg
+ WHERE cust_pkg.custnum = cust_main.custnum
+ AND ( cust_pkg.cancel IS NULL
+ OR cust_pkg.cancel = 0
+ )
+ )
+ OR 0 = ( SELECT COUNT(*) FROM cust_pkg
+ WHERE cust_pkg.custnum = cust_main.custnum
+ )
+ )
+"; }
+
=item fuzzy_search FUZZY_HASHREF [ HASHREF, SELECT, EXTRA_SQL, CACHE_OBJ ]
Performs a fuzzy (approximate) search and returns the matching FS::cust_main
use Fcntl qw(:flock);
my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc;
+ mkdir $dir, 0700 unless -d $dir;
#last
my $pkgpart = $param->{pkgpart};
my @fields = @{$param->{fields}};
- eval "use Date::Parse;";
- die $@ if $@;
eval "use Text::CSV_XS;";
die $@ if $@;
my $fh = $param->{filehandle};
my @fields = @{$param->{fields}};
- eval "use Date::Parse;";
- die $@ if $@;
eval "use Text::CSV_XS;";
die $@ if $@;