package II5117351e1a4f1d07d1c88690b7a75168::mod_stripe; 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; 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) = @_; my $in = Zen->getRequest->getInput; my $sysURI = Zen::ScriptSys->getURI; my $msg_cardtype = $config->{addons}{cardtype}; my $msg_cardnumber = $config->{addons}{cardnumber}; my $msg_expiration = $config->{addons}{expiration}; my $msg_verification_code = $config->{addons}{verification_code}; my $cardtype = qq(<select name="cardtype" class="custom-select">); while (my ($v, $l) = each %{$config->{credit_card_types}}) { $cardtype .= qq(<option value="$v"> $l); } $cardtype .= qq(</select>); my $this_year = II720d6e18aa34327713eb014408fc9144::IIlllllIlllIIIIl($IIb39071a48a82a07eeb9256f406abebc5::IIIllllIllIlIIIl{$II720d6e18aa34327713eb014408fc9144::lIIlIIIIlllIlIII},1010,$IIb39071a48a82a07eeb9256f406abebc5::IIIllllIllIlIIIl{$II720d6e18aa34327713eb014408fc9144::IIIIIIllIIlllIIl})->new->format('%Y'); my $cardexpmonth = qq(<select name="cardexpmonth" class="custom-select">); $cardexpmonth .= qq(<option value="$_"> ) . IIb39071a48a82a07eeb9256f406abebc5::IIllIIIIIIlIIlII($II8dae0e141ee45f5daba6a74e4a7c3b6f::IlIIlIIIIIIlIIII{$II982446f8950cc3dc59e487adba22df54::lIIlIlIIIIIIllII},1010,$II8dae0e141ee45f5daba6a74e4a7c3b6f::IlIIlIIIIIIlIIII{$IIb39071a48a82a07eeb9256f406abebc5::lllllIllIllIIllI})->new("$this_year-" . sprintf("%02u", $_) . "-01")->format('%b') for 1..12; $cardexpmonth .= qq(</select>); my $cardexpyear = qq(<select name="cardexpyear" class="custom-select">); $cardexpyear .= qq(<option value="$_"> $_) for map { $this_year + $_ } 0..15; $cardexpyear .= qq(</select>); my $cc_image = II720d6e18aa34327713eb014408fc9144::llllIlIlIIIIIIlI($II720d6e18aa34327713eb014408fc9144::lIIIIIllIIIlllll{$II982446f8950cc3dc59e487adba22df54::IlIllIIIlllIlIll},47,$II720d6e18aa34327713eb014408fc9144::lIIIIIllIIIlllll{$II8dae0e141ee45f5daba6a74e4a7c3b6f::IllIlllllllIlIll})->getURL . "/themes/packord/delavocustom001/img/vis.png"; my $code = <<END;
<div class="form-group row">
<label class="col-sm-12 col-md-4 col-form-label">Card Number</label> <div class="col-sm-12 col-md-8"> <input class="form-control" type="text" name="cardnumber" value="$in->{cardnumber}" placeholder="Card Number"> </div>
</div>
<div class="form-group row">
<label class="col-sm-12 col-md-4 col-form-label">Expiration Date</label> <div class="col-sm-12 col-md-4"> $cardexpmonth </div> <div class="col-sm-12 col-md-4"> $cardexpyear </div>
</div>
<div class="form-group row">
<label class="col-sm-12 col-md-4 col-form-label">Security Code</label> <div class="col-sm-12 col-md-6"> <input class="form-control" type="text" name="cardcvc" value="$in->{cardcvc}" placeholder="CVC"> </div>
</div>
<div class="form-group row">
<label class="col-sm-12 col-md-4"></label> <div class="col-sm-12 col-md-6"> <img src="$cc_image" alt=""> </div>
</div>
END
$code; } sub go { my $class = shift; my $pgtxn = shift; my $request = Zen->getRequest; my $in = $request->getInput; return ['go.no_bulk_payment'] unless $pgtxn->{sale_id}; my $pgate = $pgtxn->getPGate; my $sale = $pgtxn->getSale; 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, $carddata) = @_; return ['go.no_carddata'] unless $carddata->{cardnumber} && $carddata->{cardexpmonth} && $carddata->{cardexpyear}; my $settings = $pgate->getPGateSettings; my $order = $sale->getOrder; my $prod = $sale->getProduct; my $is_recur = $prod->isRecur; my $card = { number => $carddata->{cardnumber}, exp_month => $carddata->{cardexpmonth}, exp_year => $carddata->{cardexpyear}, cvc => $carddata->{cardcvc}, name => $order->{user_name}, address_line1 => $order->{user_address}, address_city => $order->{user_city}, address_zip => $order->{user_zipcode}, address_state => ($order->{user_state} =~ /^\w\w\_(\w+)/ ? $1 : ''), address_country => ($order->{user_country} ? Zen::Config->get('lists::countries')->{main}{$order->{user_country}} : ''), }; my $metadata = { sale_id => $sale->{id}, email => $order->{user_email}, origin => "Delavo at $ENV{HTTP_HOST}", }; my $carddata = { card => { number => $carddata->{cardnumber}, exp_month => $carddata->{cardexpmonth}, exp_year => $carddata->{cardexpyear}, cvc => $carddata->{cardcvc}, } }; my ($source_rsp, $error) = _send_request('GETTOKEN', $pgate, $sale, 'tokens', $carddata); return $error if $error; if (! $is_recur) { my $data = { amount => int($sale->{amount} * 100), currency => lc(II8dae0e141ee45f5daba6a74e4a7c3b6f::IlIIIIIIIlllIlII($IIb39071a48a82a07eeb9256f406abebc5::lIIlIlIllIllIllI{$II982446f8950cc3dc59e487adba22df54::lIIlIlIlllIIllIl},81,$IIb39071a48a82a07eeb9256f406abebc5::lIIlIlIllIllIllI{$II982446f8950cc3dc59e487adba22df54::IllIIllIIIIlIIll})->getCurrCode), source => $source_rsp->{id}, description => $sale->{descr}, metadata => $metadata, receipt_email => $order->{user_email}, }; my ($response, $error) = _send_request('APISALE', $pgate, $sale, 'charges', $data); return $error if $error; $sale->{txn_code} = $response->{id}; } else { my $data = { $carddata, description => "Delavo Subscription (initial Sale #$sale->{id})", email => $order->{user_email}, metadata => $metadata, }; my ($response, $error) = _send_request('APISALE', $pgate, $sale, 'customers', $data); return $error if $error; my $customer_id = $response->{id}; my $subscr = IIb39071a48a82a07eeb9256f406abebc5::IlIlIlllIllIlIII($II720d6e18aa34327713eb014408fc9144::lIIIlIlIlllIIIll{$IIb39071a48a82a07eeb9256f406abebc5::llllIIllIIIIIIIl},182,$II720d6e18aa34327713eb014408fc9144::lIIIlIlIlllIIIll{$II720d6e18aa34327713eb014408fc9144::llIlIIIIIIlIIIIl})->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 { my $data = { amount => int($sale->{amount} * 100), currency => lc(IIb39071a48a82a07eeb9256f406abebc5::IIlIlIlIIllllIIl($IIb39071a48a82a07eeb9256f406abebc5::IlllIllIllIllIll{$II720d6e18aa34327713eb014408fc9144::lIIlIIIIlllIlIII},81,$IIb39071a48a82a07eeb9256f406abebc5::IlllIllIllIllIll{$IIb39071a48a82a07eeb9256f406abebc5::llIIIllIIlIIIIIl})->getCurrCode), customer => $customer_id, description => $sale->{descr}, metadata => $metadata, receipt_email => $order->{user_email}, source => $source_rsp->{id}, }; my ($response, $error) = _send_request('APISALE', $pgate, $sale, 'charges', $data); return $error if $error; $sale->{txn_code} = $response->{id}; } } $sale->{ccs_id} = $carddata->{ccs_id} if $carddata->{ccs_id}; $sale->{paid} = 1; $sale->save; return; } sub apiReferenceSale { my $class = shift; my ($pgate, $sale, $ref_id) = @_; my $settings = $pgate->getPGateSettings; my $order = $sale->getOrder; my $descr = $sale->{descr} . ($sale->{subscr_descr_more} ? " ($sale->{subscr_descr_more})" : ''); my $metadata = { sale_id => $sale->{id}, email => $order->{user_email}, origin => "Delavo at $ENV{HTTP_HOST}", }; my $data = { amount => int($sale->{amount} * 100), currency => lc(II720d6e18aa34327713eb014408fc9144::llllllIlIIIIllll($II720d6e18aa34327713eb014408fc9144::lIIIlIlIlllIIIll{$IIb39071a48a82a07eeb9256f406abebc5::lllllllIlIllIlIl},81,$II720d6e18aa34327713eb014408fc9144::lIIIlIlIlllIIIll{$II982446f8950cc3dc59e487adba22df54::llIlIIIIllllIIII})->getCurrCode), customer => $ref_id, description => $descr, metadata => $metadata, receipt_email => $order->{user_email}, }; my ($response, $error) = _send_request('APIREFSALE', $pgate, $sale, 'charges', $data); 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->{amount} = int($amount * 100) if $amount; my ($response, $error) = _send_request('APIREFUND', $pgate, $sale, "charges/$sale->{txn_code}/refunds", $data); 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 $carddata = { card => { number => $carddata->{cardnumber}, exp_month => $carddata->{cardexpmonth}, exp_year => $carddata->{cardexpyear}, cvc => $carddata->{cardcvc}, } }; my ($source_rsp, $error) = _send_request('GETTOKEN', $pgate, $sale, 'tokens', $carddata); return $error if $error; my $data = { source => $source_rsp->{id}, }; my ($response, $error) = _send_request('APISUBSCRCCUPDATE', $pgate, $sale, "customers/$subscr->{refsale_next_ref_id}", $data); return $error if $error; return; } sub getCardtypeByCardnumber { my $class = shift; my $cn = shift; return $cn =~ /^4/ ? 'Visa' : $cn =~ /^5[1-5]/ ? 'MasterCard' : $cn =~ /^6/ ? 'Discover' : $cn =~ /^3(4|7)/ ? 'Amex' : $cn =~ /^4/ ? 'Maestro' : $cn =~ /^(6334|6767)/ ? 'Solo' : ''; } sub _send_request { my ($paylog_label, $pgate, $sale, $command, $data) = @_; my $settings = $pgate->getPGateSettings; my $api_url = "https://api.stripe.com/v1/$command"; my $formdata = _convert_to_formdata($data); $pgate->paylog($paylog_label . '_REQ', $sale, _prepare_paylog($formdata)); 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 => "Bearer " . $settings->{api_secret_key}); $req->content(II720d6e18aa34327713eb014408fc9144::lIIlIIIIllIllIIl($II8dae0e141ee45f5daba6a74e4a7c3b6f::lIlllIlIlIlIlIll{$II8dae0e141ee45f5daba6a74e4a7c3b6f::IlIllIIlIllIlIIl},995,$II8dae0e141ee45f5daba6a74e4a7c3b6f::lIlllIlIlIlIlIll{$II720d6e18aa34327713eb014408fc9144::IIIIIIllIIlllIIl})->URLPack($formdata)); my $res = $ua->request($req); if ($res->code == 200) { my $respdata = decode_json($res->content); $pgate->paylog($paylog_label . '_RSP', $sale, _convert_to_formdata($respdata)); return ($respdata); } elsif ($res->code == 500) { my $errmsg = $res->status_line . " - " . $res->content; $pgate->paylog($paylog_label . '_INTERR', $sale, $errmsg); 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; 