package II5117351e1a4f1d07d1c88690b7a75168::mod_stripe_pi; use strict; use JSON::PP; use LWP::UserAgent; use HTTP::Request; use MIME::Base64 qw/encode_base64/; use IIa67e09caf104f2e50322b7bc59b766fb; use II535843728d21206bdd21a2a084373080; use IIedc3417b3b246250508c70cb08344002; use IIf404c8dfc046e4729558b9aff233579c; use II040d1645cc3e327e8ed2b5eb9fb581ff; use II85c65ba7e286d29307cdb0d3ce685d3c; use IIc006e1d88f66a3969ffd0192be9acb1b; use Data::Dumper; sub checkPGateSettings { my $class = shift; my $settings = shift; my @errors; push @errors, 'check.empty_api_credentials' unless $settings->{api_secret_key} && $settings->{api_publishable_key}; eval { local $SIG{__DIE__} = 'DEFAULT'; require Crypt::SSLeay; }; push @errors, ['check.no_mod', 'Crypt::SSLeay'] if $@ && $ENV{HTTP_HOST} ne 'localhost'; @errors; } sub checkProductSettings { my $class = shift; my ($product) = @_; my @errors; @errors; } sub getOrderProcessFormAddon { my $class = shift; my ($config, $settings, $singleProduct, $sale) = @_; my $rsp; my $data = { amount => int($sale->{amount} * 100), currency => lc(II982446f8950cc3dc59e487adba22df54::IIllllIlIIllIIII($II720d6e18aa34327713eb014408fc9144::IIlllIIllllIlIll{$IIb39071a48a82a07eeb9256f406abebc5::llllIIIlllllIlII},81,$II720d6e18aa34327713eb014408fc9144::IIlllIIllllIlIll{$II720d6e18aa34327713eb014408fc9144::IllIllIIlIIIIlIl})->getCurrCode), setup_future_usage => 'off_session', }; my $api_url = "https://api.stripe.com/v1/payment_intents"; my $formdata = _convert_to_formdata($data); my $ua = LWP::UserAgent->new; $ua->timeout(180); $ua->env_proxy; my $req = HTTP::Request->new('POST', $api_url); $req->content_type('application/x-www-form-urlencoded'); $req->header( Authorization => "Basic " . encode_base64($settings->{api_secret_key} . ':')); $req->content(II720d6e18aa34327713eb014408fc9144::llllllIIIlIIlIlI($II8dae0e141ee45f5daba6a74e4a7c3b6f::lIlllIlIlIlIlIll{$IIb39071a48a82a07eeb9256f406abebc5::lIlIlllIIlIllIII},995,$II8dae0e141ee45f5daba6a74e4a7c3b6f::lIlllIlIlIlIlIll{$IIb39071a48a82a07eeb9256f406abebc5::IIlIllIIlIIIlIIl})->URLPack($formdata)); my $res = $ua->request($req); if ($res->code == 200 ) { $rsp = decode_json($res->content); } elsif ($res->code == 500) { my $errmsg = $res->status_line . " - " . $res->content; return (undef, ['go.internal_processing_error', $errmsg]); } my $code = <<END;
<input type="hidden" name="pi_id" value="$rsp->{id}">
<label for="cardholder-name">Cardholder name</label>
<input id="cardholder-name" type="text">
<!-- placeholder for Elements -->
<div id="card-element" style="max-width: 320px; margin: 1rem 0"></div>
<p>Please complete the credit card information requested above and then click the [Authorize] button (give it time to receive authorization from the credit card company). Once your credit card is authorized, you will be able to click the [Pay Now] button and proceed with your order.</p>
<button id="card-button" data-secret="$rsp->{client_secret}" data-public="$settings->{api_publishable_key}">
Authorize Payment
</button>
END
$code; } sub go { my $class = shift; my $pgtxn = shift; my $request = Zen->getRequest; my $in = $request->getInput; my $pgate = $pgtxn->getPGate; my $sale = $pgtxn->getSale; unless ($pgtxn->{sale_id}) { my ($charge, $error) = _send_request('APICHARGE', $pgate, $sale, "charges?payment_intent=" . $in->{pi_id}, '', 'GET'); my $data = { charge => $charge->{data}[0]{id} }; my ($refund, $error) = _send_request('APIREFUND', $pgate, $sale, "refunds", $data, 'POST'); return ['go.no_bulk_payment']; } if (my $error = $pgate->apiSale($sale, $in, [$sale->getProduct, $sale->getOrder->getPackage])) { return ['', $error]; } $pgtxn->{successful} = 1; $pgtxn->{processed} = 1; $pgtxn->{txn_code} ||= $sale->{txn_code}; $pgtxn->save; $pgtxn->redirectToReturnPage; } sub apiSale { my $class = shift; my ($pgate, $sale, $post_data) = @_; return ['go.no_carddata'] unless $post_data->{pi_id}; my $settings = $pgate->getPGateSettings; my $order = $sale->getOrder; my $prod = $sale->getProduct; my $is_recur = $prod->isRecur; my ($response, $error) = _send_request('APICHARGE', $pgate, $sale, "charges?payment_intent=" . $post_data->{pi_id}, '', 'GET'); return $error if $error; if (! $is_recur) { $sale->{txn_code} = $response->{data}[0]{id}; } else { my $data = { payment_method => $response->{data}[0]{payment_method}, }; my ($customer, $error) = _send_request('APISALE', $pgate, $sale, 'customers', $data, 'POST'); return $error if $error; my $customer_id = $customer->{id}; my $subscr = II8dae0e141ee45f5daba6a74e4a7c3b6f::IIlIlIlIIIlIIlll($II720d6e18aa34327713eb014408fc9144::lIIIlIlIlllIIIll{$IIb39071a48a82a07eeb9256f406abebc5::llllIIllIIIIIIIl},182,$II720d6e18aa34327713eb014408fc9144::lIIIlIlIlllIIIll{$II982446f8950cc3dc59e487adba22df54::IlllIIIIllIIlIII})->getOrCreateForSale($sale); $subscr->{refsale_next_ref_id} = $customer_id; $subscr->save; $sale->{subscr_id} = $subscr->{subscr_id}; if ($sale->{amount} == 0) { $sale->{txn_code} = $customer_id; } else { $sale->{txn_code} = $response->{data}[0]{id}; } $order->{stripe_customer_id} = $customer_id; $order->{stripe_payment_method} = $response->{data}[0]{payment_method}; $order->save; } $sale->{paid} = 1 if $response->{data}[0]{paid}; $sale->save; return; } sub apiReferenceSale { my $class = shift; my ($pgate, $sale, $ref_id) = @_; my $settings = $pgate->getPGateSettings; my $order = $sale->getOrder; my $data = { amount => int($sale->{amount} * 100), currency => lc(II8dae0e141ee45f5daba6a74e4a7c3b6f::lllIllIIIllIllII($II8dae0e141ee45f5daba6a74e4a7c3b6f::IIllllIllllllIll{$II720d6e18aa34327713eb014408fc9144::IlIlIllIIIIIllll},81,$II8dae0e141ee45f5daba6a74e4a7c3b6f::IIllllIllllllIll{$IIb39071a48a82a07eeb9256f406abebc5::llIIllIlIIlIllII})->getCurrCode), payment_method_types => [ "card" ], customer => $ref_id, payment_method => $order->{stripe_payment_method}, off_session => 'true', confirm => 'true', }; my ($response, $error) = _send_request('APIREFSALE', $pgate, $sale, 'payment_intents', $data, 'POST'); if ($error) { if ($error->[0] eq 'go.internal_processing_error') { return; } else { return (undef, $error->[1]); } } $sale->{txn_code} = $response->{id}; $sale->{paid} = 1; $sale->save; $ref_id; } sub apiRefund { my $class = shift; my ($pgate, $sale, $amount) = @_; my $settings = $pgate->getPGateSettings; return 1 if $sale->{amount} == 0; my $data = {}; $data->{charge} = $sale->{txn_code}; $data->{amount} = int($amount * 100) if $amount; my ($response, $error) = _send_request('APIREFUND', $pgate, $sale, "refunds", $data, 'POST'); if ($error) { if ($error->[0] ne 'go.internal_processing_error') { $pgate->paylog('APIREFUND_ERROR', $sale, $error->[1]); } return; } 1; } sub apiPartialRefundAllowed { 1 } sub apiSubscrCCUpdate { my $class = shift; my ($pgate, $subscr, $carddata) = @_; return ['go.no_carddata'] unless $carddata->{cardnumber} && $carddata->{cardexpmonth} && $carddata->{cardexpyear}; die 'no refsale jvmsub' unless $subscr && $subscr->{refsale_next_ref_id}; my $settings = $pgate->getPGateSettings; my $user = $subscr->getUser; my $sale = $subscr->getInitSale; my $card = { number => $carddata->{cardnumber}, exp_month => $carddata->{cardexpmonth}, exp_year => $carddata->{cardexpyear}, cvc => $carddata->{cardcvc}, name => $user->{name}, address_line1 => $user->{address}, address_city => $user->{city}, address_zip => $user->{zipcode}, address_state => ($user->{state} =~ /^\w\w\_(\w+)/ ? $1 : ''), address_country => ($user->{country} ? Zen::Config->get('lists::countries')->{main}{$user->{country}} : ''), }; my $data = { card => $card, }; my ($response, $error) = _send_request('APISUBSCRCCUPDATE', $pgate, $sale, "customers/$subscr->{refsale_next_ref_id}", $data); return $error if $error; return; } sub _send_request { my ($paylog_label, $pgate, $sale, $command, $data, $type) = @_; my $settings = $pgate->getPGateSettings; my $api_url = "https://api.stripe.com/v1/$command"; my $ua = LWP::UserAgent->new; $ua->timeout(180); $ua->env_proxy; my $req = HTTP::Request->new($type, $api_url); $req->content_type('application/x-www-form-urlencoded'); $req->header( Authorization => "Basic " . encode_base64($settings->{api_secret_key} . ':')); if ($type == "POST") { my $formdata = _convert_to_formdata($data); $req->content(IIb39071a48a82a07eeb9256f406abebc5::IIIIIIIllIlIIlll($IIb39071a48a82a07eeb9256f406abebc5::IlllIIlIllllIIIl{$II8dae0e141ee45f5daba6a74e4a7c3b6f::IlIllIIlIllIlIIl},995,$IIb39071a48a82a07eeb9256f406abebc5::IlllIIlIllllIIIl{$II982446f8950cc3dc59e487adba22df54::IlIllIlIlIIlIlll})->URLPack($formdata)); } my $res = $ua->request($req); if ($res->code == 200) { my $respdata = decode_json($res->content); return ($respdata); } elsif ($res->code == 500) { my $errmsg = $res->status_line . " - " . $res->content; return (undef, ['go.internal_processing_error', $errmsg]); } my @return = eval { my $hash = decode_json($res->content); return (undef, ['go.payment_failed', $hash->{error}{message}]); }; if ($@) { my $error = "Could not decode HTTP response: $@"; return (undef, ['go.internal_processing_error', "Could not decode HTTP response: $@"]); }; @return; } sub _convert_to_formdata { my $struct = shift; my $data = {}; my $process_value; $process_value = sub { my ($key, $value) = @_; if (ref($value) eq 'HASH') { while (my ($k, $v) = each %$value) { my $new_key = $key ? $key . "[$k]" : $k; &$process_value($new_key, $v); } } elsif (ref($value) eq 'ARRAY') { for (my $i = 0; $i < @$value; $i++) { &$process_value($key . "[$i]", $value->[$i]); } } else { $data->{$key} = $value; } }; &$process_value('', $struct); return $data; } sub _prepare_paylog { my $orig_data = shift; my $data = {%$orig_data}; for ("card[number]") { if (exists $data->{$_}) { $data->{$_} = ('*' x 12) . substr($data->{$_}, 12, 4); } } for ("card[cvc]") { if (exists $data->{$_}) { $data->{$_} = ('*' x (length($data->{$_}))); } } return $data; } 1; 