use Scalar::Util qw( blessed );
use List::Util qw( min );
use Time::Local qw(timelocal);
-use Storable qw(thaw);
-use MIME::Base64;
use Data::Dumper;
use Tie::IxHash;
use Digest::MD5 qw(md5_base64);
use FS::part_pkg_taxrate;
use FS::agent;
use FS::cust_main_invoice;
-use FS::cust_tag;
use FS::cust_credit_bill;
use FS::cust_bill_pay;
use FS::prepay_credit;
use FS::part_pkg;
use FS::part_event;
use FS::part_event_condition;
-use FS::part_export;
#use FS::cust_event;
use FS::type_pkgs;
use FS::payment_gateway;
@fuzzyfields = ( 'first', 'last', 'company', 'address1' );
@encrypted_fields = ('payinfo', 'paycvv');
-sub nohistory_fields { ('payinfo', 'paycvv'); }
+sub nohistory_fields { ('paycvv'); }
@paytypes = ('', 'Personal checking', 'Personal savings', 'Business checking', 'Business savings');
$self->invoicing_list( $invoicing_list );
}
- warn " setting customer tags\n"
- if $DEBUG > 1;
-
- foreach my $tagnum ( @{ $self->tagnum || [] } ) {
- my $cust_tag = new FS::cust_tag { 'tagnum' => $tagnum,
- 'custnum' => $self->custnum };
- my $error = $cust_tag->insert;
- if ( $error ) {
- $dbh->rollback if $oldAutoCommit;
- return $error;
- }
- }
-
- if ( $invoicing_list ) {
- $error = $self->check_invoicing_list( $invoicing_list );
- if ( $error ) {
- $dbh->rollback if $oldAutoCommit;
- #return "checking invoicing_list (transaction rolled back): $error";
- return $error;
- }
- $self->invoicing_list( $invoicing_list );
- }
-
-
warn " setting cust_main_exemption\n"
if $DEBUG > 1;
}
}
- # cust_main exports!
- warn " exporting\n" if $DEBUG > 1;
-
- my $export_args = $options{'export_args'} || [];
-
- my @part_export =
- map qsearch( 'part_export', {exportnum=>$_} ),
- $conf->config('cust_main-exports'); #, $agentnum
-
- foreach my $part_export ( @part_export ) {
- my $error = $part_export->export_insert($self, @$export_args);
- if ( $error ) {
- $dbh->rollback if $oldAutoCommit;
- return "exporting to ". $part_export->exporttype.
- " (transaction rolled back): $error";
- }
- }
-
- #foreach my $depend_jobnum ( @$depend_jobnums ) {
- # warn "[$me] inserting dependancies on supplied job $depend_jobnum\n"
- # if $DEBUG;
- # foreach my $jobnum ( @jobnums ) {
- # my $queue = qsearchs('queue', { 'jobnum' => $jobnum } );
- # warn "[$me] inserting dependancy for job $jobnum on $depend_jobnum\n"
- # if $DEBUG;
- # my $error = $queue->depend_insert($depend_jobnum);
- # if ( $error ) {
- # $dbh->rollback if $oldAutoCommit;
- # return "error queuing job dependancy: $error";
- # }
- # }
- # }
- #
- #}
- #
- #if ( exists $options{'jobnums'} ) {
- # push @{ $options{'jobnums'} }, @jobnums;
- #}
-
warn " insert complete; committing transaction\n"
if $DEBUG > 1;
}
}
- foreach my $table (qw( cust_main_invoice cust_main_exemption cust_tag )) {
- foreach my $record ( qsearch( 'table', { 'custnum' => $self->custnum } ) ) {
- my $error = $record->delete;
- if ( $error ) {
- $dbh->rollback if $oldAutoCommit;
- return $error;
- }
+ foreach my $cust_main_invoice ( #(email invoice destinations, not invoices)
+ qsearch( 'cust_main_invoice', { 'custnum' => $self->custnum } )
+ ) {
+ my $error = $cust_main_invoice->delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ foreach my $cust_main_exemption (
+ qsearch( 'cust_main_exemption', { 'custnum' => $self->custnum } )
+ ) {
+ my $error = $cust_main_exemption->delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
}
}
return $error;
}
- # cust_main exports!
-
- #my $export_args = $options{'export_args'} || [];
-
- my @part_export =
- map qsearch( 'part_export', {exportnum=>$_} ),
- $conf->config('cust_main-exports'); #, $agentnum
-
- foreach my $part_export ( @part_export ) {
- my $error = $part_export->export_delete( $self ); #, @$export_args);
- if ( $error ) {
- $dbh->rollback if $oldAutoCommit;
- return "exporting to ". $part_export->exporttype.
- " (transaction rolled back): $error";
- }
- }
-
$dbh->commit or die $dbh->errstr if $oldAutoCommit;
'';
$self->invoicing_list( $invoicing_list );
}
- if ( $self->exists('tagnum') ) { #so we don't delete these on edit by accident
-
- #this could be more efficient than deleting and re-inserting, if it matters
- foreach my $cust_tag (qsearch('cust_tag', {'custnum'=>$self->custnum} )) {
- my $error = $cust_tag->delete;
- if ( $error ) {
- $dbh->rollback if $oldAutoCommit;
- return $error;
- }
- }
- foreach my $tagnum ( @{ $self->tagnum || [] } ) {
- my $cust_tag = new FS::cust_tag { 'tagnum' => $tagnum,
- 'custnum' => $self->custnum };
- my $error = $cust_tag->insert;
- if ( $error ) {
- $dbh->rollback if $oldAutoCommit;
- return $error;
- }
- }
-
- }
-
my %options = @param;
my $tax_exemption = delete $options{'tax_exemption'};
}
- if ( $self->payby =~ /^(CARD|CHEK|LECB)$/
- && ( ( $self->get('payinfo') ne $old->get('payinfo')
- && $self->get('payinfo') !~ /^99\d{14}$/
- )
- || grep { $self->get($_) ne $old->get($_) } qw(paydate payname)
- )
- )
- {
-
+ if ( $self->payby =~ /^(CARD|CHEK|LECB)$/ &&
+ grep { $self->get($_) ne $old->get($_) } qw(payinfo paydate payname) ) {
# card/check/lec info has changed, want to retry realtime_ invoice events
my $error = $self->retry_realtime;
if ( $error ) {
}
}
- # cust_main exports!
-
- my $export_args = $options{'export_args'} || [];
-
- my @part_export =
- map qsearch( 'part_export', {exportnum=>$_} ),
- $conf->config('cust_main-exports'); #, $agentnum
-
- foreach my $part_export ( @part_export ) {
- my $error = $part_export->export_replace( $self, $old, @$export_args);
- if ( $error ) {
- $dbh->rollback if $oldAutoCommit;
- return "exporting to ". $part_export->exporttype.
- " (transaction rolled back): $error";
- }
- }
-
$dbh->commit or die $dbh->errstr if $oldAutoCommit;
'';
# If it is encrypted and the private key is not availaible then we can't
# check the credit card.
- my $check_payinfo = ! $self->is_encrypted($self->payinfo);
+
+ my $check_payinfo = 1;
+
+ if ($self->is_encrypted($self->payinfo)) {
+ $check_payinfo = 0;
+ }
if ( $check_payinfo && $self->payby =~ /^(CARD|DCRD)$/ ) {
or return gettext('invalid_card'); # . ": ". $self->payinfo;
return gettext('unknown_card_type')
- if $self->payinfo !~ /^99\d{14}$/ #token
- && cardtype($self->payinfo) eq "Unknown";
+ if cardtype($self->payinfo) eq "Unknown";
my $ban = qsearchs('banned_pay', $self->_banned_pay_hashref);
if ( $ban ) {
return 1 if !$a_num_cust_svc && $b_num_cust_svc;
my @a_cust_svc = $a->cust_svc;
my @b_cust_svc = $b->cust_svc;
- return 0 if !scalar(@a_cust_svc) && !scalar(@b_cust_svc);
- return -1 if scalar(@a_cust_svc) && !scalar(@b_cust_svc);
- return 1 if !scalar(@a_cust_svc) && scalar(@b_cust_svc);
$a_cust_svc[0]->svc_x->label cmp $b_cust_svc[0]->svc_x->label;
}
qsearchs( 'agent', { 'agentnum' => $self->agentnum } );
}
-=item agent_name
-
-Returns the agent name (see L<FS::agent>) for this customer.
-
-=cut
-
-sub agent_name {
- my $self = shift;
- $self->agent->agent;
-}
-
-=item cust_tag
-
-Returns any tags associated with this customer, as FS::cust_tag objects,
-or an empty list if there are no tags.
-
-=cut
-
-sub cust_tag {
- my $self = shift;
- qsearch('cust_tag', { 'custnum' => $self->custnum } );
-}
-
-=item part_tag
-
-Returns any tags associated with this customer, as FS::part_tag objects,
-or an empty list if there are no tags.
-
-=cut
-
-sub part_tag {
- my $self = shift;
- map $_->part_tag, $self->cust_tag;
-}
-
-
=item cust_class
Returns the customer class, as an FS::cust_class object, or the empty string
Debugging level. Default is 0 (no debugging), or can be set to 1 (passed-in options), 2 (traces progress), 3 (more information), or 4 (include full search queries)
-=item job
-
-Optional FS::queue entry to receive status updates.
-
=back
Options are passed to the B<bill> and B<collect> methods verbatim, so all
#pre-printing invoices
$options{'actual_time'} ||= time;
- my $job = $options{'job'};
- $job->update_statustext('0,cleaning expired packages') if $job;
$error = $self->cancel_expired_pkgs( $options{actual_time} );
if ( $error ) {
$error = "Error expiring custnum ". $self->custnum. ": $error";
else { warn $error; }
}
- $job->update_statustext('20,billing packages') if $job;
$error = $self->bill( %options );
if ( $error ) {
$error = "Error billing custnum ". $self->custnum. ": $error";
else { warn $error; }
}
- $job->update_statustext('50,applying payments and credits') if $job;
$error = $self->apply_payments_and_credits;
if ( $error ) {
$error = "Error applying custnum ". $self->custnum. ": $error";
else { warn $error; }
}
- $job->update_statustext('70,running collection events') if $job;
unless ( $conf->exists('cancelled_cust-noevents')
&& ! $self->num_ncancelled_pkgs
) {
else { warn $error; }
}
}
- $job->update_statustext('100,finished') if $job;
'';
local $FS::UID::AutoCommit = 0;
my $dbh = dbh;
- warn "$me acquiring lock on customer ". $self->custnum. "\n"
- if $DEBUG;
-
$self->select_for_update; #mutex
- warn "$me running pre-bill events for customer ". $self->custnum. "\n"
- if $DEBUG;
-
my $error = $self->do_cust_event(
'debug' => ( $options{'debug'} || 0 ),
'time' => $invoice_time,
return $error;
}
- warn "$me done running pre-bill events for customer ". $self->custnum. "\n"
- if $DEBUG;
-
#keep auto-charge and non-auto-charge line items separate
my @passes = ( '', 'no_auto' );
}
}
- $dbh->commit or die $dbh->errstr if $oldAutoCommit;
-
- #never want to roll back an event just because it returned an error
- local $FS::UID::AutoCommit = 1; #$oldAutoCommit;
-
- $self->do_cust_event(
+ my $error = $self->do_cust_event(
'debug' => ( $options{'debug'} || 0 ),
'time' => $invoice_time,
'check_freq' => $options{'check_freq'},
'stage' => 'collect',
);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ '';
}
return $due_cust_event;
}
- $dbh->commit or die $dbh->errstr if $oldAutoCommit;
- #never want to roll back an event just because it or a different one
- # returned an error
- local $FS::UID::AutoCommit = 1; #$oldAutoCommit;
-
foreach my $cust_event ( @$due_cust_event ) {
#XXX lock event
unless ( $cust_event->test_conditions( 'time' => $time ) ) {
#don't leave stray "new/locked" records around
my $error = $cust_event->delete;
- return $error if $error;
+ if ( $error ) {
+ #gah, even with transactions
+ $dbh->commit if $oldAutoCommit; #well.
+ return $error;
+ }
next;
}
warn " running cust_event ". $cust_event->eventnum. "\n"
if $DEBUG > 1;
+
#if ( my $error = $cust_event->do_event(%options) ) { #XXX %options?
if ( my $error = $cust_event->do_event() ) {
#XXX wtf is this? figure out a proper dealio with return value
#from do_event
- return $error;
- }
+ # gah, even with transactions.
+ $dbh->commit if $oldAutoCommit; #well.
+ return $error;
+ }
}
}
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
'';
}
$options->{payment_gateway}->gatewaynum
? $options->{payment_gateway}->options
: @{ $options->{payment_gateway}->get('options') };
-
}
sub _bop_defaults {
my ($self, $options) = @_;
my %content = ();
+ $content{address} = exists($options->{'address1'})
+ ? $options->{'address1'}
+ : $self->address1;
+ my $address2 = exists($options->{'address2'})
+ ? $options->{'address2'}
+ : $self->address2;
+ $content{address} .= ", ". $address2 if length($address2);
+
my $payip = exists($options->{'payip'}) ? $options->{'payip'} : $self->payip;
$content{customer_ip} = $payip if length($payip);
( $conf->exists('business-onlinepayment-email_customer')
|| $conf->exists('business-onlinepayment-email-override') );
- my ($payname, $payfirst, $paylast);
- if ( $options->{payname} && $options->{method} ne 'ECHECK' ) {
- ($payname = $options->{payname}) =~
- /^\s*([\w \,\.\-\']*)?\s+([\w\,\.\-\']+)\s*$/
- or return "Illegal payname $payname";
- ($payfirst, $paylast) = ($1, $2);
- } else {
- $payfirst = $self->getfield('first');
- $paylast = $self->getfield('last');
- $payname = "$payfirst $paylast";
- }
-
- $content{last_name} = $paylast;
- $content{first_name} = $payfirst;
+ $content{payfirst} = $self->getfield('first');
+ $content{paylast} = $self->getfield('last');
- $content{name} = $payname;
+ $content{account_name} = "$content{payfirst} $content{paylast}"
+ if $options->{method} eq 'ECHECK';
- $content{address} = exists($options->{'address1'})
- ? $options->{'address1'}
- : $self->address1;
- my $address2 = exists($options->{'address2'})
- ? $options->{'address2'}
- : $self->address2;
- $content{address} .= ", ". $address2 if length($address2);
+ $content{name} = $options->{payname};
+ $content{name} = $content{account_name} if exists($content{account_name});
$content{city} = exists($options->{city})
? $options->{city}
$content{country} = exists($options->{country})
? $options->{country}
: $self->country;
-
$content{referer} = 'http://cleanwhisker.420.am/'; #XXX fix referer :/
$content{phone} = $self->daytime || $self->night;
- \%content;
+ (%content);
}
my %bop_method2payby = (
# massage data
###
- my $bop_content = $self->_bop_content(\%options);
- return $bop_content unless ref($bop_content);
+ my (%bop_content) = $self->_bop_content(\%options);
+
+ if ( $options{method} ne 'ECHECK' ) {
+ $options{payname} =~ /^\s*([\w \,\.\-\']*)?\s+([\w\,\.\-\']+)\s*$/
+ or return "Illegal payname $options{payname}";
+ ($bop_content{payfirst}, $bop_content{paylast}) = ($1, $2);
+ }
my @invoicing_list = $self->invoicing_list_emailonly;
if ( $conf->exists('emailinvoiceautoalways')
$content{account_type} = exists($options{'paytype'})
? uc($options{'paytype'}) || 'CHECKING'
: uc($self->getfield('paytype')) || 'CHECKING';
- $content{account_name} = $self->getfield('first'). ' '.
- $self->getfield('last');
-
$content{customer_org} = $self->company ? 'B' : 'I';
$content{state_id} = exists($options{'stateid'})
? $options{'stateid'}
'amount' => $options{amount},
#'invoice_number' => $options{'invnum'},
'customer_id' => $self->custnum,
- %$bop_content,
+ %bop_content,
'reference' => $cust_pay_pending->paypendingnum, #for now
'email' => $email,
%content, #after
my $BOP_TESTING_SUCCESS = 1;
unless ( $BOP_TESTING ) {
- $transaction->test_transaction(1)
- if $conf->exists('business-onlinepayment-test_transaction');
$transaction->submit();
} else {
if ( $BOP_TESTING_SUCCESS ) {
$capture->content( %capture );
- $capture->test_transaction(1)
- if $conf->exists('business-onlinepayment-test_transaction');
$capture->submit();
unless ( $capture->is_success ) {
}
###
- # Tokenize
- ###
-
-
- if ( $transaction->can('card_token') && $transaction->card_token ) {
-
- $self->card_token($transaction->card_token);
-
- if ( $options{'payinfo'} eq $self->payinfo ) {
- $self->payinfo($transaction->card_token);
- my $error = $self->replace;
- if ( $error ) {
- warn "WARNING: error storing token: $error, but proceeding anyway\n";
- }
- }
-
- }
-
- ###
# result handling
###
'paid' => $cust_pay_pending->paid,
'_date' => '',
'payby' => $cust_pay_pending->payby,
- 'payinfo' => $options{'payinfo'},
+ #'payinfo' => $payinfo,
'paybatch' => $paybatch,
'paydate' => $cust_pay_pending->paydate,
'pkgnum' => $cust_pay_pending->pkgnum,
my $self = shift;
my %options = ();
- if (ref($_[0]) eq 'HASH') {
+ if (ref($_[0]) ne 'HASH') {
%options = %{$_[0]};
} else {
my $method = shift;
}
}
$void->content( 'action' => 'void', %content );
- $void->test_transaction(1)
- if $conf->exists('business-onlinepayment-test_transaction');
$void->submit();
if ( $void->is_success ) {
my $error = $cust_pay->void($options{'reason'});
);
warn join('', map { " $_ => $sub_content{$_}\n" } keys %sub_content )
if $DEBUG > 1;
- $refund->test_transaction(1)
- if $conf->exists('business-onlinepayment-test_transaction');
$refund->submit();
return "$processor error: ". $refund->error_message
my $self = shift;
my $time = shift;
- my $custnum = $self->custnum;
-
- my $owed_sql = FS::cust_bill->owed_sql;
-
- my $sql = "
- SELECT SUM($owed_sql) FROM cust_bill
- WHERE custnum = $custnum
- AND _date <= $time
- ";
+# my $custnum = $self->custnum;
+#
+# my $owed_sql = FS::cust_bill->owed_sql;
+#
+# my $sql = "
+# SELECT SUM($owed_sql) FROM cust_bill
+# WHERE custnum = $custnum
+# AND _date <= $time
+# ";
+#
+# my $sth = dbh->prepare($sql) or die dbh->errstr;
+# $sth->execute() or die $sth->errstr;
+#
+# return sprintf( '%.2f', $sth->fetchrow_arrayref->[0] );
- sprintf( "%.2f", $self->scalar_sql($sql) );
+ my $total_bill = 0;
+ foreach my $cust_bill (
+ grep { $_->_date <= $time }
+ qsearch('cust_bill', { 'custnum' => $self->custnum, } )
+ ) {
+ $total_bill += $cust_bill->owed;
+ }
+ sprintf( "%.2f", $total_bill );
}
sub total_unapplied_credits {
my $self = shift;
-
- my $custnum = $self->custnum;
-
- my $unapplied_sql = FS::cust_credit->unapplied_sql;
-
- my $sql = "
- SELECT SUM($unapplied_sql) FROM cust_credit
- WHERE custnum = $custnum
- ";
-
- sprintf( "%.2f", $self->scalar_sql($sql) );
-
+ my $total_credit = 0;
+ $total_credit += $_->credited foreach $self->cust_credit;
+ sprintf( "%.2f", $total_credit );
}
=item total_unapplied_credits_pkgnum PKGNUM
sub total_unapplied_payments {
my $self = shift;
-
- my $custnum = $self->custnum;
-
- my $unapplied_sql = FS::cust_pay->unapplied_sql;
-
- my $sql = "
- SELECT SUM($unapplied_sql) FROM cust_pay
- WHERE custnum = $custnum
- ";
-
- sprintf( "%.2f", $self->scalar_sql($sql) );
-
+ my $total_unapplied = 0;
+ $total_unapplied += $_->unapplied foreach $self->cust_pay;
+ sprintf( "%.2f", $total_unapplied );
}
=item total_unapplied_payments_pkgnum PKGNUM
sub total_unapplied_refunds {
my $self = shift;
- my $custnum = $self->custnum;
-
- my $unapplied_sql = FS::cust_refund->unapplied_sql;
-
- my $sql = "
- SELECT SUM($unapplied_sql) FROM cust_refund
- WHERE custnum = $custnum
- ";
-
- sprintf( "%.2f", $self->scalar_sql($sql) );
-
+ my $total_unapplied = 0;
+ $total_unapplied += $_->unapplied foreach $self->cust_refund;
+ sprintf( "%.2f", $total_unapplied );
}
=item balance
sub balance {
my $self = shift;
- $self->balance_date_range;
+ sprintf( "%.2f",
+ $self->total_owed
+ + $self->total_unapplied_refunds
+ - $self->total_unapplied_credits
+ - $self->total_unapplied_payments
+ );
}
=item balance_date TIME
sub balance_date {
my $self = shift;
- $self->balance_date_range(shift);
+ my $time = shift;
+ sprintf( "%.2f",
+ $self->total_owed_date($time)
+ + $self->total_unapplied_refunds
+ - $self->total_unapplied_credits
+ - $self->total_unapplied_payments
+ );
}
-=item balance_date_range [ START_TIME [ END_TIME [ OPTION => VALUE ... ] ] ]
+=item balance_date_range START_TIME [ END_TIME [ OPTION => VALUE ... ] ]
-Returns the balance for this customer, optionally considering invoices with
-date earlier than START_TIME, and not later than END_TIME
+Returns the balance for this customer, only considering invoices with date
+earlier than START_TIME, and optionally not later than END_TIME
(total_owed_date minus total_unapplied_credits minus total_unapplied_payments).
Times are specified as SQL fragments or numeric
=item prospect - No packages have ever been ordered
-=item ordered - Recurring packages all are new (not yet billed).
-
=item active - One or more recurring packages is active
=item inactive - No active recurring packages, but otherwise unsuspended/uncancelled (the inactive status is new - previously inactive customers were mis-identified as cancelled)
sub cust_status {
my $self = shift;
- # prospect ordered active inactive suspended cancelled
- for my $status ( FS::cust_main->statuses() ) {
+ for my $status (qw( prospect active inactive suspended cancelled )) {
my $method = $status.'_sql';
my $numnum = ( my $sql = $self->$method() ) =~ s/cust_main\.custnum/?/g;
my $sth = dbh->prepare("SELECT $sql") or die dbh->errstr;
tie %statuscolor, 'Tie::IxHash',
'prospect' => '7e0079', #'000000', #black? naw, purple
'active' => '00CC00', #green
- 'ordered' => '009999', #teal? cyan?
'inactive' => '0000CC', #blue
'suspended' => 'FF9900', #yellow
'cancelled' => 'FF0000', #red
$select_count_pkgs;
}
-sub prospect_sql {
- " 0 = ( $select_count_pkgs ) ";
-}
-
-=item ordered_sql
-
-Returns an SQL expression identifying ordered cust_main records (customers with
-recurring packages not yet setup).
-
-=cut
-
-sub ordered_sql {
- " 0 < ( $select_count_pkgs AND ". FS::cust_pkg->ordered_sql. " ) ";
-}
+sub prospect_sql { "
+ 0 = ( $select_count_pkgs )
+"; }
=item active_sql
=cut
-sub active_sql {
- " 0 < ( $select_count_pkgs AND ". FS::cust_pkg->active_sql. " ) ";
-}
+sub active_sql { "
+ 0 < ( $select_count_pkgs AND ". FS::cust_pkg->active_sql. "
+ )
+"; }
=item inactive_sql
WHERE cust_refund.custnum = cust_main.custnum )
"; }
-=item balance_date_sql [ START_TIME [ END_TIME [ OPTION => VALUE ... ] ] ]
+=item balance_date_sql START_TIME [ END_TIME [ OPTION => VALUE ... ] ]
-Returns an SQL fragment to retreive the balance for this customer, optionally
-considering invoices with date earlier than START_TIME, and not
+Returns an SQL fragment to retreive the balance for this customer, only
+considering invoices with date earlier than START_TIME, and optionally not
later than END_TIME (total_owed_date minus total_unapplied_credits minus
total_unapplied_payments).
=cut
sub unapplied_payments_date_sql {
- my( $class, $start, $end, %opt ) = @_;
+ my( $class, $start, $end, ) = @_;
- my $cutoff = $opt{'cutoff'};
-
- my $unapp_pay = FS::cust_pay->unapplied_sql($cutoff);
+ my $unapp_pay = FS::cust_pay->unapplied_sql;
my $pay_where = $class->_money_table_where( 'cust_pay', $start, $end,
'unapplied_date'=>1 );
# parse status
##
- #prospect ordered active inactive suspended cancelled
+ #prospect active inactive suspended cancelled
if ( grep { $params->{'status'} eq $_ } FS::cust_main->statuses() ) {
my $method = $params->{'status'}. '_sql';
#push @where, $class->$method();
my $subject = delete $params->{subject};
my $html_body = delete $params->{html_body};
my $text_body = delete $params->{text_body};
- my $error = '';
- my $job = delete $params->{'job'}
- or die "email_search_result must run from the job queue.\n";
+ my $job = delete $params->{'job'};
$params->{'payby'} = [ split(/\0/, $params->{'payby'}) ]
unless ref($params->{'payby'});
my( $num, $last, $min_sec ) = (0, time, 5); #progresbar foo
- my @retry_jobs = ();
- my $success = 0;
#eventually order+limit magic to reduce memory use?
foreach my $cust_main ( qsearch($sql_query) ) {
- #progressbar first, so that the count is right
- $num++;
- if ( time - $min_sec > $last ) {
- my $error = $job->update_statustext(
- int( 100 * $num / $num_cust )
- );
- die $error if $error;
- $last = time;
- }
-
my $to = $cust_main->invoicing_list_emailonly_scalar;
+ next unless $to;
- if( $to ) {
- my @message = (
+ my $error = send_email(
+ generate_email(
'from' => $from,
'to' => $to,
'subject' => $subject,
'html_body' => $html_body,
'text_body' => $text_body,
- );
-
- $error = send_email( generate_email( @message ) );
+ )
+ );
+ return $error if $error;
- if($error) {
- # queue the sending of this message so that the user can see what we
- # tried to do, and retry if desired
- my $queue = new FS::queue {
- 'job' => 'FS::Misc::process_send_email',
- 'custnum' => $cust_main->custnum,
- 'status' => 'failed',
- 'statustext' => $error,
- };
- $queue->insert(@message);
- push @retry_jobs, $queue;
- }
- else {
- $success++;
+ if ( $job ) { #progressbar foo
+ $num++;
+ if ( time - $min_sec > $last ) {
+ my $error = $job->update_statustext(
+ int( 100 * $num / $num_cust )
+ );
+ die $error if $error;
+ $last = time;
}
}
- if($success == 0 and
- (scalar(@retry_jobs) > 10 or $num == $num_cust)
- ) {
- # 10 is arbitrary, but if we have enough failures, that's
- # probably a configuration or network problem, and we
- # abort the batch and run away screaming.
- # We NEVER do this if anything was successfully sent.
- $_->delete foreach (@retry_jobs);
- return "multiple failures: '$error'\n";
- }
- }
-
- if(@retry_jobs) {
- # fail the job, but with a status message that makes it clear
- # something was sent.
- return "Sent $success, failed ".scalar(@retry_jobs).". Failed attempts placed in job queue.\n";
}
return '';
}
+use Storable qw(thaw);
+use Data::Dumper;
+use MIME::Base64;
sub process_email_search_result {
my $job = shift;
#warn "$me process_re_X $method for job $job\n" if $DEBUG;
}
-=item queued_bill 'custnum' => CUSTNUM [ , OPTION => VALUE ... ]
-
-Subroutine (not a method), designed to be called from the queue.
-
-Takes a list of options and values.
-
-Pulls up the customer record via the custnum option and calls bill_and_collect.
-
-=cut
-
sub queued_bill {
+ ## actual sub, not a method, designed to be called from the queue.
+ ## sets up the customer, and calls the bill_and_collect
my (%args) = @_; #, ($time, $invoice_time, $check_freq, $resetup) = @_;
-
my $cust_main = qsearchs( 'cust_main', { custnum => $args{'custnum'} } );
- warn 'bill_and_collect custnum#'. $cust_main->custnum. "\n";#log custnum w/pid
-
- $cust_main->bill_and_collect( %args );
-}
-
-sub process_bill_and_collect {
- my $job = shift;
- my $param = thaw(decode_base64(shift));
- my $cust_main = qsearchs( 'cust_main', { custnum => $param->{'custnum'} } )
- or die "custnum '$param->{custnum}' not found!\n";
- $param->{'job'} = $job;
- $param->{'fatal'} = 1; # runs from job queue, will be caught
- $param->{'retry'} = 1;
-
- $cust_main->bill_and_collect( %$param );
+ $cust_main->bill_and_collect(
+ %args,
+ );
}
sub _upgrade_data { #class method
$sth->execute or die $sth->errstr;
local($ignore_expired_card) = 1;
- local($skip_fuzzyfiles) = 1;
$class->_upgrade_otaker(%opts);
}