Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
executable file 197 lines (175 sloc) 5.62 KB
#!/usr/bin/env perl
use 5.14.1;
use Dancer qw/:syntax/;
use Dancer::Plugin::Email;
use FindBin;
use Cwd qw/realpath/;
use lib "$FindBin::Bin/../lib";
use Biopay::Member;
use Biopay::Prices;
use Biopay::PaymentProcessor;
use Biopay::Receipt;
use Biopay::Transaction;
use Getopt::Long;
use Biopay::Util qw/email_admin email_board host/;
use List::Util qw/sum/;
use Try::Tiny;
BEGIN {
Dancer::Config::setting('appdir',realpath("$FindBin::Bin/.."));
Dancer::Config::setting('views',realpath("$FindBin::Bin/../views"));
Dancer::Config::load();
}
my $force;
my $verbose = 1;
my $dont_send_email;
GetOptions(
'f|force' => \$force,
'v|verbose' => \$verbose,
'd|dont-send' => \$dont_send_email,
);
my $member_id = shift || die "USAGE: $0 <member_id>";;
my $member = Biopay::Member->By_id($member_id);
if ($member->billing_error and !$force) {
print "Member $member_id has a billing error. Use --force if you are sure.\n";
exit 0;
}
my $txns = $member->unpaid_transactions;
unless (@$txns) {
print "Member $member_id has no un-paid transactions. Exiting.\n";
exit 0;
}
print "Member $member_id has @{[scalar(@$txns)]} unpaid transactions.\n" if $verbose;
my $total = sum map { $_->price } @$txns;
print ' (Bio-' . $member->id . ":\$$total) ";
my $items = [
map { { amount => $_->price, type => 'txn', desc => $_->txn_id } }
@$txns
];
my $order_num = @$txns > 1
? sprintf("%d-txns-%d", @$txns+0, time)
: "txn-" . $txns->[0]->txn_id;
my $need_to_renew_membership = $member->membership_is_expired;
my $membership_price = Biopay::Prices->new->annual_membership_price;
if ($need_to_renew_membership) {
$total += $membership_price;
push @$items, {
amount => $membership_price,
type => 'dues',
desc => 'Membership Dues',
};
}
use Data::Dumper;
print Dumper $items if $verbose;
my $error = "Order '$order_num' not yet processed.";
eval {
my ($ok, $msg) = Biopay::PaymentProcessor->new->process(
order_num => $order_num,
amount => $total,
hash => $member->payment_hash,
);
print "Processed payment: ($ok, @{[$msg||'']})\n" if $verbose;
if (!$ok) {
my $err = $msg;
print "Error processing payment for @{[$member->id]} - $err";
# There was an error processing payment for this member. Set their
# billing_error flag, so that we don't retry until it is cleared
try {
$member->billing_error($err);
$member->billing_error_epoch(time());
$member->frozen(1);
$member->save;
print ' (Freeze:' . $member->id . ') ';
$member->send_billing_error_email($err, $total) unless $dont_send_email;
}
catch {
my $save_err = $_;
email_admin("Failed to set billing_error for member",
"I tried to mark member " . $member->id . " with a "
. "billing error for order '$order_num' but failed."
. "\nSave error was: $save_err"
. "\nPayment error was: $err");
};
create_freeze_job($member, 'freeze');
print "Transaction failed. Exiting.\n" if $verbose;
exit 0;
}
Biopay::Receipt->Create(
member_id => $member->id,
order_num => $order_num,
amount => $total,
items => $items,
);
$error = "Processed payment, but didn't update member yet.";
# Update the member, if necessary
if ($need_to_renew_membership) {
$member->renew_membership;
print ' (Renewed membership for: ' . $member->id . ') ';
}
unfreeze_member($member) if $member->frozen;
$error = "Order '$order_num' processed but txns not marked as paid.";
for my $txn (@$txns) {
print " (Marking " . $txn->id . " as paid) ";
$txn->paid(1);
try {
$txn->save;
}
catch {
my $err = $_;
email_admin("Failed to mark txn:" . $txn->id . " as paid!",
"I was trying to mark it as paid after successfully "
. " processing order $order_num for \$$total\n\n$err"
);
};
}
$error = "Order '$order_num' processed, txns marked as paid, but "
. "receipt is not sent.";
if ($dont_send_email) {
print "Skipping receipt!\n";
}
else {
system($^X, "$FindBin::Bin/send-receipt", '--for', $member->id);
}
};
if (my $err = $@) {
error $err;
email_admin("Error processing payment $order_num",
"Had a problem during payment processing: $error\n\n$err\n\n"
. "This payment was for member ID " . $member->id
. " (" . host() . '/members/' . $member->id . ') '
. " for transactions: " . join(', ', map { host() . '/txns/' . $_->id } @$txns)
);
}
print "Transaction complete. Exiting.\n";
exit 0;
sub create_freeze_job {
my $member = shift;
my $type = shift;
try {
Biopay::Command->Create(
command => $type,
member_id => $member->id,
);
}
catch {
my $err = $_;
email_admin("Failed to $type @{[$member->id]}",
"I failed to create a $type job for $member->id.\n\n"
. "Error: $err");
};
}
sub unfreeze_member {
my $member = shift;
$member->frozen(0);
create_freeze_job($member, 'unfreeze');
try {
$member->save;
print ' (Un-freeze:' . $member->id . ') ';
}
catch {
my $err = $_;
email_admin("Failed to un-freeze member",
"I tried to un-freeze member " . $member->id
. " after a successful payment, but saving failed."
. "\nError was: $err");
};
}