summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--FS/FS/Conf.pm30
-rw-r--r--FS/FS/cust_bill.pm56
-rw-r--r--FS/FS/cust_bill_ApplicationCommon.pm7
-rw-r--r--FS/FS/cust_bill_pay.pm19
-rw-r--r--FS/FS/cust_bill_pay_pkg.pm78
-rw-r--r--FS/FS/cust_main.pm21
-rw-r--r--FS/FS/cust_pay.pm275
-rwxr-xr-xhttemplate/edit/process/cust_pay.cgi2
-rw-r--r--httemplate/edit/process/elements/ApplicationCommon.html2
9 files changed, 355 insertions, 135 deletions
diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm
index d8e111b..ea83c6c 100644
--- a/FS/FS/Conf.pm
+++ b/FS/FS/Conf.pm
@@ -1015,11 +1015,22 @@ worry that config_items is freeside-specific and icky.
{
'key' => 'payment_receipt_email',
'section' => 'billing',
- 'description' => 'Template file for payment receipts. Payment receipts are sent to the customer email invoice destination(s) when a payment is received. See the <a href="http://search.cpan.org/dist/Text-Template/lib/Text/Template.pm">Text::Template</a> documentation for details on the template substitution language. The following variables are available: <ul><li><code>$date</code> <li><code>$name</code> <li><code>$paynum</code> - Freeside payment number <li><code>$paid</code> - Amount of payment <li><code>$payby</code> - Payment type (Card, Check, Electronic check, etc.) <li><code>$payinfo</code> - Masked credit card number or check number <li><code>$balance</code> - New balance</ul>',
+ 'description' => 'Template file for payment receipts. Payment receipts are sent to the customer email invoice destination(s) when a payment is received. See the <a href="http://search.cpan.org/dist/Text-Template/lib/Text/Template.pm">Text::Template</a> documentation for details on the template substitution language. The following variables are available: <ul><li><code>$date</code> <li><code>$name</code> <li><code>$paynum</code> - Freeside payment number <li><code>$paid</code> - Amount of payment <li><code>$payby</code> - Payment type (Card, Check, Electronic check, etc.) <li><code>$payinfo</code> - Masked credit card number or check number <li><code>$balance</code> - New balance<li><code>$pkg</code> - Package (requires payment_receipt-trigger set to cust_bill_pay_pkg)</ul>',
'type' => [qw( checkbox textarea )],
},
{
+ 'key' => 'payment_receipt-trigger',
+ 'section' => 'billing',
+ 'description' => 'When payment receipts are triggered. Defaults to when payment is made.',
+ 'type' => 'select',
+ 'select_hash' => [
+ 'cust_pay' => 'When payment is made.',
+ 'cust_bill_pay_pkg' => 'When payment is applied.',
+ ],
+ },
+
+ {
'key' => 'lpr',
'section' => 'required',
'description' => 'Print command for paper invoices, for example `lpr -h\'',
@@ -2487,6 +2498,14 @@ worry that config_items is freeside-specific and icky.
},
{
+ 'key' => 'dashboard-install_welcome',
+ 'section' => 'UI',
+ 'description' => 'New install welcome screen.',
+ 'type' => 'select',
+ 'select_enum' => [ '', 'ITSP_fsinc_hosted', ],
+ },
+
+ {
'key' => 'dashboard-toplist',
'section' => 'UI',
'description' => 'List of items to display on the top of the front page',
@@ -2769,7 +2788,14 @@ worry that config_items is freeside-specific and icky.
{
'key' => 'cust_main-default_agent_custid',
'section' => 'UI',
- 'description' => 'Display the agent_custid field instead of the custnum field.',
+ 'description' => 'Display the agent_custid field when available instead of the custnum field.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'cust_bill-default_agent_invid',
+ 'section' => 'UI',
+ 'description' => 'Display the agent_invid field when available instead of the invnum field.',
'type' => 'checkbox',
},
diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm
index 03c1c1d..f6c5eeb 100644
--- a/FS/FS/cust_bill.pm
+++ b/FS/FS/cust_bill.pm
@@ -16,6 +16,7 @@ use FS::Misc qw( send_email send_fax generate_ps generate_pdf do_print );
use FS::Record qw( qsearch qsearchs dbh );
use FS::cust_main_Mixin;
use FS::cust_main;
+use FS::cust_statement;
use FS::cust_bill_pkg;
use FS::cust_bill_pkg_display;
use FS::cust_credit;
@@ -82,6 +83,8 @@ owes you money. The specific charges are itemized as B<cust_bill_pkg> records
(see L<FS::cust_bill_pkg>). FS::cust_bill inherits from FS::Record. The
following fields are currently supported:
+Regular fields
+
=over 4
=item invnum - primary key (assigned automatically for new invoices)
@@ -93,10 +96,26 @@ L<Time::Local> and L<Date::Parse> for conversion functions.
=item charged - amount of this invoice
+=back
+
+Deprecated
+
+=over 4
+
=item printed - deprecated
+=back
+
+Specific use cases
+
+=over 4
+
=item closed - books closed flag, empty or `Y'
+=item statementnum - invoice aggregation (see L<FS::cust_statement>)
+
+=item agent_invid - legacy invoice number
+
=back
=head1 METHODS
@@ -183,17 +202,16 @@ sub check {
my $error =
$self->ut_numbern('invnum')
- || $self->ut_number('custnum')
+ || $self->ut_foreign_key('custnum', 'cust_main', 'custnum' )
|| $self->ut_numbern('_date')
|| $self->ut_money('charged')
|| $self->ut_numbern('printed')
|| $self->ut_enum('closed', [ '', 'Y' ])
+ || $self->ut_foreign_keyn('statementnum', 'cust_statement', 'statementnum' )
+ || $self->ut_numbern('agent_invid') #varchar?
;
return $error if $error;
- return "Unknown customer"
- unless qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
-
$self->_date(time) unless $self->_date;
$self->printed(0) if $self->printed eq '';
@@ -201,6 +219,22 @@ sub check {
$self->SUPER::check;
}
+=item display_invnum
+
+Returns the displayed invoice number for this invoice: agent_invid if
+cust_bill-default_agent_invid is set and it has a value, invnum otherwise.
+
+=cut
+
+sub display_invnum {
+ my $self = shift;
+ if ( $conf->exists('cust_bill-default_agent_invid') && $self->agent_invid ){
+ return $self->agent_invid;
+ } else {
+ return $self->invnum;
+ }
+}
+
=item previous
Returns a list consisting of the total previous balance for this customer,
@@ -531,12 +565,20 @@ sub owed_pkgnum {
$balance;
}
-=item apply_payments_and_credits
+=item apply_payments_and_credits [ OPTION => VALUE ... ]
+
+Applies unapplied payments and credits to this invoice.
+
+A hash of optional arguments may be passed. Currently "manual" is supported.
+If true, a payment receipt is sent instead of a statement when
+'payment_receipt_email' configuration option is set.
+
+If there is an error, returns the error, otherwise returns false.
=cut
sub apply_payments_and_credits {
- my $self = shift;
+ my( $self, %options ) = @_;
local $SIG{HUP} = 'IGNORE';
local $SIG{INT} = 'IGNORE';
@@ -633,7 +675,7 @@ sub apply_payments_and_credits {
$app->invnum( $self->invnum );
- my $error = $app->insert;
+ my $error = $app->insert(%options);
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
return "Error inserting ". $app->table. " record: $error";
diff --git a/FS/FS/cust_bill_ApplicationCommon.pm b/FS/FS/cust_bill_ApplicationCommon.pm
index d4627c0..7449679 100644
--- a/FS/FS/cust_bill_ApplicationCommon.pm
+++ b/FS/FS/cust_bill_ApplicationCommon.pm
@@ -56,7 +56,7 @@ sub insert {
my $dbh = dbh;
my $error = $self->SUPER::insert(@_)
- || $self->apply_to_lineitems;
+ || $self->apply_to_lineitems(@_);
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
return $error;
@@ -113,7 +113,8 @@ Auto-applies this invoice application to specific line items, if possible.
=cut
sub apply_to_lineitems {
- my $self = shift;
+ #my $self = shift;
+ my( $self, %options ) = @_;
return '' if $skip_apply_to_lineitems_hack;
@@ -322,7 +323,7 @@ sub apply_to_lineitems {
'sdate' => $cust_bill_pkg->sdate,
'edate' => $cust_bill_pkg->edate,
});
- my $error = $application->insert;
+ my $error = $application->insert(%options);
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
return $error;
diff --git a/FS/FS/cust_bill_pay.pm b/FS/FS/cust_bill_pay.pm
index e1b02ae..831d7f2 100644
--- a/FS/FS/cust_bill_pay.pm
+++ b/FS/FS/cust_bill_pay.pm
@@ -150,6 +150,25 @@ sub cust_pay {
qsearchs( 'cust_pay', { 'paynum' => $self->paynum } );
}
+=item send_receipt HASHREF | OPTION => VALUE ...
+
+
+Sends a payment receipt for the associated payment, against this specific
+invoice. If there is an error, returns the error, otherwise returns false.
+
+See L<FS::cust_pay/send_receipt>.
+
+=cut
+
+sub send_receipt {
+ my $self = shift;
+ my $opt = ref($_[0]) ? shift : { @_ };
+ $self->cust_pay->send_receipt(
+ 'cust_bill' => $self->cust_bill,
+ %$opt,
+ );
+}
+
=back
=head1 BUGS
diff --git a/FS/FS/cust_bill_pay_pkg.pm b/FS/FS/cust_bill_pay_pkg.pm
index cdbace9..48c4364 100644
--- a/FS/FS/cust_bill_pay_pkg.pm
+++ b/FS/FS/cust_bill_pay_pkg.pm
@@ -2,7 +2,10 @@ package FS::cust_bill_pay_pkg;
use strict;
use vars qw( @ISA );
+use FS::Conf;
use FS::Record qw( qsearch qsearchs );
+use FS::cust_bill_pay;
+use FS::cust_bill_pkg;
@ISA = qw(FS::Record);
@@ -77,7 +80,39 @@ otherwise returns false.
=cut
-# the insert method can be inherited from FS::Record
+sub insert {
+ my($self, %options) = @_;
+
+ #local $SIG{HUP} = 'IGNORE';
+ #local $SIG{INT} = 'IGNORE';
+ #local $SIG{QUIT} = 'IGNORE';
+ #local $SIG{TERM} = 'IGNORE';
+ #local $SIG{TSTP} = 'IGNORE';
+ #local $SIG{PIPE} = 'IGNORE';
+ #
+ #my $oldAutoCommit = $FS::UID::AutoCommit;
+ #local $FS::UID::AutoCommit = 0;
+ #my $dbh = dbh;
+
+ my $error = $self->SUPER::insert;
+ if ( $error ) {
+ #$dbh->rollback if $oldAutoCommit;
+ return "error inserting $self: $error";
+ }
+
+ #payment receipt
+ my $conf = new FS::Conf;
+ my $trigger = $conf->config('payment_receipt-trigger') || 'cust_pay';
+ if ( $trigger eq 'cust_bill_pay_pkg' ) {
+ my $error = $self->send_receipt(
+ 'manual' => $options{'manual'},
+ );
+ warn "can't send payment receipt/statement: $error" if $error;
+ }
+
+ '';
+
+}
=item delete
@@ -124,6 +159,47 @@ sub check {
$self->SUPER::check;
}
+=item cust_bill_pay
+
+Returns the FS::cust_bill_pay object (payment application to the overall
+invoice).
+
+=cut
+
+sub cust_bill_pay {
+ my $self = shift;
+ qsearchs('cust_bill_pay', { 'billpaynum' => $self->billpaynum } );
+}
+
+=item cust_bill_pkg
+
+Returns the FS::cust_bill_pkg object (line item to which payment is applied).
+
+=cut
+
+sub cust_bill_pkg {
+ my $self = shift;
+ qsearchs('cust_bill_pkg', { 'billpkgnum' => $self->billpkgnum } );
+}
+
+=item send_receipt
+
+Sends a payment receipt for the associated payment, against this specific
+invoice and packages. If there is an error, returns the error, otherwise
+returns false.
+
+=cut
+
+sub send_receipt {
+ my $self = shift;
+ my $opt = ref($_[0]) ? shift : { @_ };
+ $self->cust_bill_pay->send_receipt(
+ 'cust_pkg' => $self->cust_bill_pkg->cust_pkg,
+ %$opt,
+ );
+}
+
+
=back
=head1 BUGS
diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm
index bf95fa9..9f85e79 100644
--- a/FS/FS/cust_main.pm
+++ b/FS/FS/cust_main.pm
@@ -6168,19 +6168,23 @@ sub batch_card {
'';
}
-=item apply_payments_and_credits
+=item apply_payments_and_credits [ OPTION => VALUE ... ]
Applies unapplied payments and credits.
In most cases, this new method should be used in place of sequential
apply_payments and apply_credits methods.
+A hash of optional arguments may be passed. Currently "manual" is supported.
+If true, a payment receipt is sent instead of a statement when
+'payment_receipt_email' configuration option is set.
+
If there is an error, returns the error, otherwise returns false.
=cut
sub apply_payments_and_credits {
- my $self = shift;
+ my( $self, %options ) = @_;
local $SIG{HUP} = 'IGNORE';
local $SIG{INT} = 'IGNORE';
@@ -6196,7 +6200,7 @@ sub apply_payments_and_credits {
$self->select_for_update; #mutex
foreach my $cust_bill ( $self->open_cust_bill ) {
- my $error = $cust_bill->apply_payments_and_credits;
+ my $error = $cust_bill->apply_payments_and_credits(%options);
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
return "Error applying: $error";
@@ -6305,19 +6309,24 @@ sub apply_credits {
return $total_unapplied_credits;
}
-=item apply_payments
+=item apply_payments [ OPTION => VALUE ... ]
Applies (see L<FS::cust_bill_pay>) unapplied payments (see L<FS::cust_pay>)
to outstanding invoice balances in chronological order.
#and returns the value of any remaining unapplied payments.
+A hash of optional arguments may be passed. Currently "manual" is supported.
+If true, a payment receipt is sent instead of a statement when
+'payment_receipt_email' configuration option is set.
+
+
Dies if there is an error.
=cut
sub apply_payments {
- my $self = shift;
+ my( $self, %options ) = @_;
local $SIG{HUP} = 'IGNORE';
local $SIG{INT} = 'IGNORE';
@@ -6381,7 +6390,7 @@ sub apply_payments {
} );
$cust_bill_pay->pkgnum( $payment->pkgnum )
if $conf->exists('pkg-balances') && $payment->pkgnum;
- my $error = $cust_bill_pay->insert;
+ my $error = $cust_bill_pay->insert(%options);
if ( $error ) {
$dbh->rollback or die $dbh->errstr if $oldAutoCommit;
die $error;
diff --git a/FS/FS/cust_pay.pm b/FS/FS/cust_pay.pm
index e1e6df2..69bcd87 100644
--- a/FS/FS/cust_pay.pm
+++ b/FS/FS/cust_pay.pm
@@ -132,21 +132,22 @@ sub cust_unlinked_msg {
' (cust_pay.paynum '. $self->paynum. ')';
}
-=item insert
+=item insert [ OPTION => VALUE ... ]
Adds this payment to the database.
For backwards-compatibility and convenience, if the additional field invnum
is defined, an FS::cust_bill_pay record for the full amount of the payment
-will be created. In this case, custnum is optional. An hash of optional
-arguments may be passed. Currently "manual" is supported. If true, a
-payment receipt is sent instead of a statement when 'payment_receipt_email'
-configuration option is set.
+will be created. In this case, custnum is optional.
+
+A hash of optional arguments may be passed. Currently "manual" is supported.
+If true, a payment receipt is sent instead of a statement when
+'payment_receipt_email' configuration option is set.
=cut
sub insert {
- my ($self, %options) = @_;
+ my($self, %options) = @_;
local $SIG{HUP} = 'IGNORE';
local $SIG{INT} = 'IGNORE';
@@ -169,7 +170,6 @@ sub insert {
$self->custnum($cust_bill->custnum );
}
-
my $error = $self->check;
return $error if $error;
@@ -189,7 +189,7 @@ sub insert {
'amount' => $self->paid,
'_date' => $self->_date,
};
- $error = $cust_bill_pay->insert;
+ $error = $cust_bill_pay->insert(%options);
if ( $error ) {
if ( $ignore_noapply ) {
warn "warning: error inserting $cust_bill_pay: $error ".
@@ -216,74 +216,15 @@ sub insert {
$dbh->commit or die $dbh->errstr if $oldAutoCommit;
- #my $cust_main = $self->cust_main;
- if ( $conf->exists('payment_receipt_email')
- && grep { $_ !~ /^(POST|FAX)$/ } $cust_main->invoicing_list
- ) {
-
- $cust_bill ||= ($cust_main->cust_bill)[-1]; #rather inefficient though?
-
- my $error;
- if ( ( exists($options{'manual'}) && $options{'manual'} )
- || ! $conf->exists('invoice_html_statement')
- || ! $cust_bill
- ) {
-
- my $receipt_template = new Text::Template (
- TYPE => 'ARRAY',
- SOURCE => [ map "$_\n", $conf->config('payment_receipt_email') ],
- ) or do {
- warn "can't create payment receipt template: $Text::Template::ERROR";
- return '';
- };
-
- my @invoicing_list = grep { $_ !~ /^(POST|FAX)$/ }
- $cust_main->invoicing_list;
-
- my $payby = $self->payby;
- my $payinfo = $self->payinfo;
- $payby =~ s/^BILL$/Check/ if $payinfo;
- if ( $payby eq 'CARD' || $payby eq 'CHEK' ) {
- $payinfo = $self->paymask
- } else {
- $payinfo = $self->decrypt($payinfo);
- }
- $payby =~ s/^CHEK$/Electronic check/;
-
- $error = send_email(
- 'from' => $conf->config('invoice_from', $cust_main->agentnum),
- #invoice_from??? well as good as any
- 'to' => \@invoicing_list,
- 'subject' => 'Payment receipt',
- 'body' => [ $receipt_template->fill_in( HASH => {
- 'date' => time2str("%a %B %o, %Y", $self->_date),
- 'name' => $cust_main->name,
- 'paynum' => $self->paynum,
- 'paid' => sprintf("%.2f", $self->paid),
- 'payby' => ucfirst(lc($payby)),
- 'payinfo' => $payinfo,
- 'balance' => $cust_main->balance,
- 'company_name' => $conf->config('company_name'),
- } ) ],
- );
-
- } else {
-
- my $queue = new FS::queue {
- 'paynum' => $self->paynum,
- 'job' => 'FS::cust_bill::queueable_email',
- };
- $error = $queue->insert(
- 'invnum' => $cust_bill->invnum,
- 'template' => 'statement',
- );
-
- }
-
- if ( $error ) {
- warn "can't send payment receipt/statement: $error";
- }
-
+ #payment receipt
+ my $trigger = $conf->config('payment_receipt-trigger') || 'cust_pay';
+ if ( $trigger eq 'cust_pay' ) {
+ my $error = $self->send_receipt(
+ 'manual' => $options{'manual'},
+ 'cust_bill' => $cust_bill,
+ 'cust_main' => $cust_main,
+ );
+ warn "can't send payment receipt/statement: $error" if $error;
}
'';
@@ -471,58 +412,109 @@ sub check {
$self->SUPER::check;
}
-=item batch_insert CUST_PAY_OBJECT, ...
+=item send_receipt HASHREF | OPTION => VALUE ...
-Class method which inserts multiple payments. Takes a list of FS::cust_pay
-objects. Returns a list, each element representing the status of inserting the
-corresponding payment - empty. If there is an error inserting any payment, the
-entire transaction is rolled back, i.e. all payments are inserted or none are.
+Sends a payment receipt for this payment..
-For example:
+Available options:
- my @errors = FS::cust_pay->batch_insert(@cust_pay);
- my $num_errors = scalar(grep $_, @errors);
- if ( $num_errors == 0 ) {
- #success; all payments were inserted
- } else {
- #failure; no payments were inserted.
- }
+=over 4
+
+=item manual
+
+Flag indicating the payment is being made manually.
+
+=item cust_bill
+
+Invoice (FS::cust_bill) object. If not specified, the most recent invoice
+will be assumed.
+
+=item cust_main
+
+Customer (FS::cust_main) object (for efficiency).
+
+=back
=cut
-sub batch_insert {
- my $self = shift; #class method
+sub send_receipt {
+ my $self = shift;
+ my $opt = ref($_[0]) ? shift : { @_ };
- local $SIG{HUP} = 'IGNORE';
- local $SIG{INT} = 'IGNORE';
- local $SIG{QUIT} = 'IGNORE';
- local $SIG{TERM} = 'IGNORE';
- local $SIG{TSTP} = 'IGNORE';
- local $SIG{PIPE} = 'IGNORE';
+ my $cust_bill = $opt->{'cust_bill'};
+ my $cust_main = $opt->{'cust_main'} || $self->cust_main;
- my $oldAutoCommit = $FS::UID::AutoCommit;
- local $FS::UID::AutoCommit = 0;
- my $dbh = dbh;
+ my $conf = new FS::Conf;
- my $errors = 0;
-
- my @errors = map {
- my $error = $_->insert( 'manual' => 1 );
- if ( $error ) {
- $errors++;
+ return ''
+ unless $conf->exists('payment_receipt_email')
+ && grep { $_ !~ /^(POST|FAX)$/ } $cust_main->invoicing_list;
+
+ $cust_bill ||= ($cust_main->cust_bill)[-1]; #rather inefficient though?
+
+ if ( ( exists($opt->{'manual'}) && $opt->{'manual'} )
+ || ! $conf->exists('invoice_html_statement')
+ || ! $cust_bill
+ ) {
+
+ my $receipt_template = new Text::Template (
+ TYPE => 'ARRAY',
+ SOURCE => [ map "$_\n", $conf->config('payment_receipt_email') ],
+ ) or do {
+ warn "can't create payment receipt template: $Text::Template::ERROR";
+ return '';
+ };
+
+ my @invoicing_list = grep { $_ !~ /^(POST|FAX)$/ }
+ $cust_main->invoicing_list;
+
+ my $payby = $self->payby;
+ my $payinfo = $self->payinfo;
+ $payby =~ s/^BILL$/Check/ if $payinfo;
+ if ( $payby eq 'CARD' || $payby eq 'CHEK' ) {
+ $payinfo = $self->paymask
} else {
- $_->cust_main->apply_payments;
+ $payinfo = $self->decrypt($payinfo);
}
- $error;
- } @_;
+ $payby =~ s/^CHEK$/Electronic check/;
+
+ my %fill_in = (
+ 'date' => time2str("%a %B %o, %Y", $self->_date),
+ 'name' => $cust_main->name,
+ 'paynum' => $self->paynum,
+ 'paid' => sprintf("%.2f", $self->paid),
+ 'payby' => ucfirst(lc($payby)),
+ 'payinfo' => $payinfo,
+ 'balance' => $cust_main->balance,
+ 'company_name' => $conf->config('company_name', $cust_main->agentnum),
+ );
+
+ if ( $opt->{'cust_pkg'} ) {
+ $fill_in{'pkg'} = $opt->{'cust_pkg'}->part_pkg->pkg;
+ #setup date, other things?
+ }
+
+ send_email(
+ 'from' => $conf->config('invoice_from', $cust_main->agentnum),
+ #invoice_from??? well as good as any
+ 'to' => \@invoicing_list,
+ 'subject' => 'Payment receipt',
+ 'body' => [ $receipt_template->fill_in( HASH => \%fill_in ) ],
+ );
- if ( $errors ) {
- $dbh->rollback if $oldAutoCommit;
} else {
- $dbh->commit or die $dbh->errstr if $oldAutoCommit;
- }
- @errors;
+ my $queue = new FS::queue {
+ 'paynum' => $self->paynum,
+ 'job' => 'FS::cust_bill::queueable_email',
+ };
+
+ $queue->insert(
+ 'invnum' => $cust_bill->invnum,
+ 'template' => 'statement',
+ );
+
+ }
}
@@ -603,6 +595,61 @@ sub amount {
=over 4
+=item batch_insert CUST_PAY_OBJECT, ...
+
+Class method which inserts multiple payments. Takes a list of FS::cust_pay
+objects. Returns a list, each element representing the status of inserting the
+corresponding payment - empty. If there is an error inserting any payment, the
+entire transaction is rolled back, i.e. all payments are inserted or none are.
+
+For example:
+
+ my @errors = FS::cust_pay->batch_insert(@cust_pay);
+ my $num_errors = scalar(grep $_, @errors);
+ if ( $num_errors == 0 ) {
+ #success; all payments were inserted
+ } else {
+ #failure; no payments were inserted.
+ }
+
+=cut
+
+sub batch_insert {
+ my $self = shift; #class method
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $errors = 0;
+
+ my @errors = map {
+ my $error = $_->insert( 'manual' => 1 );
+ if ( $error ) {
+ $errors++;
+ } else {
+ $_->cust_main->apply_payments;
+ }
+ $error;
+ } @_;
+
+ if ( $errors ) {
+ $dbh->rollback if $oldAutoCommit;
+ } else {
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ }
+
+ @errors;
+
+}
+
=item unapplied_sql
Returns an SQL fragment to retreive the unapplied amount.
diff --git a/httemplate/edit/process/cust_pay.cgi b/httemplate/edit/process/cust_pay.cgi
index f8ac8b1..a310c53 100755
--- a/httemplate/edit/process/cust_pay.cgi
+++ b/httemplate/edit/process/cust_pay.cgi
@@ -7,7 +7,7 @@
% if ( $cgi->param('apply') eq 'yes' ) {
% my $cust_main = qsearchs('cust_main', { 'custnum' => $linknum })
% or die "unknown custnum $linknum";
-% $cust_main->apply_payments;
+% $cust_main->apply_payments( 'manual' => 1 );
% }
% if ( $link eq 'popup' ) {
%
diff --git a/httemplate/edit/process/elements/ApplicationCommon.html b/httemplate/edit/process/elements/ApplicationCommon.html
index 2782dc2..e0c5bd7 100644
--- a/httemplate/edit/process/elements/ApplicationCommon.html
+++ b/httemplate/edit/process/elements/ApplicationCommon.html
@@ -72,6 +72,6 @@ my $new;
#}
-my $error = $new->insert;
+my $error = $new->insert( 'manual' => 1 );
</%init>