use Date::Format 'time2str';
my %opt;
-getopts("r:f:ca:g:s:e:vn", \%opt);
+getopts("r:f:ca:g:s:e:vnX:", \%opt);
$user = shift or die &usage;
&adminsuidsetup( $user );
or die "Agent has no payment gateway for method '$method'.";
}
+if(defined($opt{'X'}) and !qsearchs('reason', { reasonnum => opt{'X'} })) {
+ die "Cancellation reason not found: '".$opt{'X'}."'";
+}
+
my ($processor, $login, $password, $action, @bop_options) =
FS::cust_main->default_payment_gateway($method);
my $gatewaynum = '';
$opt{'r'} ||= 'freeside-void-payments';
my $success = 0;
my $notfound = 0;
+my $canceled = 0;
print "Voiding ".scalar(@auths)." transactions:\n" if $opt{'v'};
foreach my $authnum (@auths) {
- my $paybatch = $gatewaynum . $processor . ':' . $authnum;
- my $cust_pay = qsearchs('cust_pay', { paybatch => $paybatch } );
+ my $cust_pay = qsearchs('cust_pay', {
+ gatewaynum => $gatewaynum,
+ processor => $processor,
+ authorization => $authnum,
+ });
my $error;
+ my $cancel_error;
if($cust_pay) {
$error = $cust_pay->void($opt{'r'});
$success++ if not $error;
+ if($opt{'X'} and not $error) {
+ $cancel_error = join(';',$cust_pay->cust_main->cancel('reason' => $opt{'X'}));
+ $canceled++ if !$cancel_error;
+ }
}
else {
- my $cpv = qsearchs('cust_pay_void', { paybatch => $paybatch });
+ my $cpv = qsearchs('cust_pay_void', {
+ gatewaynum => $gatewaynum,
+ processor => $processor,
+ authorization => $authnum,
+ });
if($cpv) {
$error = 'already voided '.time2str('%Y-%m-%d', $cpv->void_date) .
' by ' . $cpv->otaker;
}
if($opt{'v'}) {
print $authnum;
- print "\t($error)" if $error;
+ if($error) {
+ print "\t($error)";
+ }
+ elsif($opt{'X'}) {
+ print "\t(canceled service)" if !$cancel_error;
+ print "\n\t(cancellation failed: $cancel_error)" if $cancel_error;
+ }
print "\n";
}
}
if($opt{'v'}) {
print scalar(@auths)." transactions: $success voided, $notfound not found\n";
+ print "$canceled customer".($canceled == 1 ? '' : 's')." canceled\n" if $opt{'X'};
}
sub usage {
- die "Usage:\n\n freeside-void-payments [ -f file | [ -s start-date ] [ -e end-date ] ] [ -r 'reason' ] [ -g gatewaynum | -a agentnum ] [ -c ] [ -v ] [ -n ]user\n";
+ die "Usage:\n\n freeside-void-payments [ options ] user
+
+ options:
+ -a agentnum use agentnum's gateway information
+ -g gatewaynum use gatewaynum
+ -f file read transaction numbers from file
+ -c use ECHECK gateway instead of CARD
+ -r reason specify void reason (as a string)
+ -v be verbose
+ -s start-date
+ -e end-date limit by payment return date
+ -X reasonnum cancel customers whose payments are voided
+ (specify cancellation reason number)
+
+";
}
__END__
=head1 SYNOPSIS
- freeside-void-payments [ -f file | [ -s start-date ] [ -e end-date ] ] [ -r 'reason' ] [ -g gatewaynum | -a agentnum ] [ -c ] [ -v ] [ -n ] user
+ freeside-void-payments [ -f file | [ -s start-date ] [ -e end-date ] ]
+ [ -r 'reason' ]
+ [ -g gatewaynum | -a agentnum ]
+ [ -c ] [ -v ]
+ [ -X reasonnum ]
+ user
=head1 DESCRIPTION
+=pod
+
Voids payments that were returned by the payment processor. Can be
run periodically from crontab or manually after receiving a list of
returned payments. Normally this is a meaningful operation only for
-f: Read the list of authorization numbers from the specified file.
If they are not from the default payment gateway, -g or -a
must be given to identify the gateway.
-
+
If -f is not given, the script will attempt to contact the gateway
and download a list of returned transactions. To support this,
the Business::OnlinePayment module for the processor must implement
- the I<get_returns()> method. For an example, see
- L<Business::OnlinePayment::WesternACH>.
+ the get_returns() method. For an example, see
+ Business::OnlinePayment::WesternACH.
-s, -e: Specify the starting and ending dates for the void list.
This has no effect if -f is given. The end date defaults to
-r: The reason for voiding the payments, to be stored in the database.
- -g: The L<FS::payment_gateway> number for the gateway that handled
+ -g: The FS::payment_gateway number for the gateway that handled
these payments. If -f is not given, this determines which
gateway will be contacted. This overrides -a.
credit cards.
-v: Be verbose.
-
-A warning will be emitted for each transaction that can't be found.
-This may happen if it's already been voided, or if the gateway
-doesn't match.
+
+ -X: Automatically cancel all packages belonging to customers whose
+ payments were returned. Requires a cancellation reasonnum
+ (from FS::reason).
=head1 EXAMPLE
=head1 BUGS
-Most payment gateways don't support it, making the script largely useless.
+Most payment gateways don't support it.
=head1 SEE ALSO