From ca4b9bc0beb61e7cb9337c0287c90fd2cf33df97 Mon Sep 17 00:00:00 2001 From: Thom McGrath Date: Fri, 28 Jun 2024 14:42:00 +0000 Subject: [PATCH] Making payment methods data-driven --- Website/framework/classes/BeaconStripeAPI.php | 50 +++++++++++-- Website/www/omni/begin.php | 67 +++++++++-------- Website/www/omni/index.php | 73 +++++++++++-------- 3 files changed, 123 insertions(+), 67 deletions(-) diff --git a/Website/framework/classes/BeaconStripeAPI.php b/Website/framework/classes/BeaconStripeAPI.php index 89072c3ee..88157c180 100644 --- a/Website/framework/classes/BeaconStripeAPI.php +++ b/Website/framework/classes/BeaconStripeAPI.php @@ -9,10 +9,12 @@ public function __construct(string $apiSecret, string $stripeVersion = '2020-08- $this->stripeVersion = $stripeVersion; } - protected function GetURL(string $url): ?array { - $json = BeaconCache::Get($url); - if (is_null($json) === false) { - return $json; + protected function GetURL(string $url, bool $noCache = true): ?array { + if ($noCache === false) { + $json = BeaconCache::Get($url); + if (is_null($json) === false) { + return $json; + } } $curl = curl_init($url); @@ -34,7 +36,9 @@ protected function GetURL(string $url): ?array { return null; } - BeaconCache::Set($url, $json, 300); + if ($noCache === false) { + BeaconCache::Set($url, $json, 300); + } return $json; } @@ -240,7 +244,7 @@ public function CreateCheckoutSession(array $details): ?array { } public function GetCountrySpec(string $countryCode): ?array { - return $this->GetURL('https://api.stripe.com/v1/country_specs/' . $countryCode); + return $this->GetURL('https://api.stripe.com/v1/country_specs/' . $countryCode, false); } public function UpdatedProductPrice(string $priceId, int $amount): string|bool { @@ -323,6 +327,40 @@ public function EditPrice(string $price_id, array $changes): ?array { public function EditProduct(string $product_code, array $changes): ?array { return $this->PostURL('https://api.stripe.com/v1/products/' . $product_code, $changes); } + + public function GetValueLists(string|array|null $containing = null): ?array { + $lists = $this->GetURL('https://api.stripe.com/v1/radar/value_lists?limit=100'); + if (is_null($lists)) { + return null; + } + + if (is_null($containing)) { + return $lists; + } elseif (is_string($containing)) { + $containing = [$containing]; + } + $containing = array_map('strtolower', $containing); + $filtered = []; + foreach ($lists['data'] as $list) { + $items = $list['list_items']['data']; + foreach ($items as $item) { + $value = strtolower($item['value']); + if (in_array($value, $containing)) { + $filtered[] = $list; + break; + } + } + } + return $filtered; + } + + public function GetFailuresByCustomer(string $customerId): ?array { + $charges = $this->GetURL('https://api.stripe.com/v1/charges/search?query=' . urlencode("customer:'{$customerId}' AND status:'failed'")); + if (is_null($charges)) { + return null; + } + return $charges['data']; + } } ?> diff --git a/Website/www/omni/begin.php b/Website/www/omni/begin.php index d30956c8e..082c5fb41 100644 --- a/Website/www/omni/begin.php +++ b/Website/www/omni/begin.php @@ -53,42 +53,18 @@ $database = BeaconCommon::Database(); if (isset($_COOKIE['beacon_affiliate'])) { - $client_reference_id = $_COOKIE['beacon_affiliate']; + $clientReferenceId = $_COOKIE['beacon_affiliate']; - $rows = $database->Query('SELECT purchase_id, code FROM affiliate_tracking WHERE client_reference_id = $1;', $client_reference_id); + $rows = $database->Query('SELECT purchase_id, code FROM affiliate_tracking WHERE client_reference_id = $1;', $clientReferenceId); if ($rows->RecordCount() === 1 && is_null($rows->Field('purchase_id')) === false) { // need a new id - $client_reference_id = BeaconShop::TrackAffiliateClick($rows->Field('code')); + $clientReferenceId = BeaconShop::TrackAffiliateClick($rows->Field('code')); } } else { - $client_reference_id = BeaconCommon::GenerateUUID(); + $clientReferenceId = BeaconCommon::GenerateUUID(); } -$payment_methods = ['card']; -switch ($currency) { -case 'EUR': - $payment_methods[] = 'ideal'; - $payment_methods[] = 'bancontact'; - $payment_methods[] = 'p24'; - $payment_methods[] = 'eps'; - break; -case 'PLN': - $payment_methods[] = 'p24'; - break; -} - -$payment = [ - 'client_reference_id' => $client_reference_id, - 'customer_email' => $email, - 'payment_method_types' => $payment_methods, - 'mode' => 'payment', - 'success_url' => BeaconCommon::AbsoluteURL('/omni/welcome/'), - 'cancel_url' => BeaconCommon::AbsoluteURL('/omni#checkout'), - 'billing_address_collection' => 'required', - 'automatic_tax' => ['enabled' => 'true'], - 'line_items' => [], -]; - +$userIsSuspect = false; $user = null; $licenses = []; try { @@ -100,7 +76,7 @@ if (is_null($user) === false) { if ($user->IsBanned()) { http_response_code(400); - echo json_encode(['error' => true, 'message' => 'An ichthyornis stole my shotgun!'], JSON_PRETTY_PRINT); + echo json_encode(['error' => true, 'message' => 'Stripe was unable to start the checkout session.'], JSON_PRETTY_PRINT); exit; } $payment['metadata']['Beacon User UUID'] = $user->UserID(); @@ -134,6 +110,30 @@ } $api = new BeaconStripeAPI(BeaconCommon::GetGlobal('Stripe_Secret_Key')); +if ($userIsSuspect === false) { + $valueLists = $api->GetValueLists([$email, BeaconCommon::RemoteAddr(false)]); + $userIsSuspect = is_null($valueLists) || count($valueLists) > 0; +} + +$paymentMethodRows = $database->Query('SELECT code FROM public.find_payment_methods($1, $2);', $currency, $userIsSuspect); +$paymentMethods = []; +while (!$paymentMethodRows->EOF()) { + $paymentMethods[] = $paymentMethodRows->Field('code'); + $paymentMethodRows->MoveNext(); +} + +$payment = [ + 'client_reference_id' => $clientReferenceId, + 'customer_email' => $email, + 'payment_method_types' => $paymentMethods, + 'mode' => 'payment', + 'success_url' => BeaconCommon::AbsoluteURL('/omni/welcome/'), + 'cancel_url' => BeaconCommon::AbsoluteURL('/omni#checkout'), + 'billing_address_collection' => 'required', + 'automatic_tax' => ['enabled' => 'true'], + 'line_items' => [], +]; + try { $customers = $api->GetCustomersByEmail($email); if (is_null($customers) === false && is_array($customers) && array_key_exists('data', $customers) && count($customers['data']) >= 1) { @@ -141,6 +141,11 @@ $payment['customer'] = $customer['id']; $payment['customer_update'] = ['address' => 'auto', 'name' => 'auto']; unset($payment['customer_email']); + + if ($userIsSuspect === false) { + $failures = $api->GetFailuresByCustomer($customer['id']); + $userIsSuspect = is_null($failures) || count($failures) >= 3; + } } } catch (Exception $err) { } @@ -333,7 +338,7 @@ http_response_code(200); echo json_encode([ 'error' => false, - 'client_reference_id' => $client_reference_id, + 'client_reference_id' => $clientReferenceId, 'url' => $session['url'] ], JSON_PRETTY_PRINT); diff --git a/Website/www/omni/index.php b/Website/www/omni/index.php index 0ffce02ac..48e8c8028 100644 --- a/Website/www/omni/index.php +++ b/Website/www/omni/index.php @@ -60,37 +60,50 @@ $arkSAEnabled = isset($productDetails['ArkSA']); $palworldEnabled = isset($productDetails['Palworld']); -$paymentMethods = [ - 'Universal' => ['apple', 'google', 'mastercard', 'visa', 'amex', 'discover', 'dinersclub', 'jcb'], - 'EUR' => ['bancontact', 'eps', 'ideal', 'p24'], - 'PLN' => ['p24'], -]; -$paymentLabels = [ - 'apple' => 'Apple Pay', - 'google' => 'Google Pay', - 'mastercard' => 'Mastercard', - 'visa' => 'Visa', - 'amex' => 'American Express', - 'discover' => 'Discover', - 'dinersclub' => 'Diner\'s Club', - 'jcb' => 'JCB', - 'bancontact' => 'Bancontact', - 'eps' => 'EPS', - 'ideal' => 'iDEAL', - 'p24' => 'Przelewy24', -]; - -$supportedPaymentMethods = $paymentMethods['Universal']; -if (array_key_exists($currency, $paymentMethods)) { - $supportedPaymentMethods = array_merge($supportedPaymentMethods, $paymentMethods[$currency]); -} +$paymentMethodRows = $database->Query('SELECT * FROM public.find_payment_methods($1, FALSE);', $currency); $paymentMethodInfo = []; -foreach ($supportedPaymentMethods as $payment_method) { - $paymentMethodInfo[] = [ - 'key' => $payment_method, - 'label' => $paymentLabels[$payment_method], - 'iconUrl' => BeaconCommon::AssetURI('paymethod_' . $payment_method . '.svg') - ]; +while (!$paymentMethodRows->EOF()) { + $code = $paymentMethodRows->Field('code'); + if ($code === 'card') { + $paymentMethodInfo[] = [ + 'label' => 'Apple Pay', + 'iconUrl' => BeaconCommon::AssetURI('paymethod_apple.svg'), + ]; + $paymentMethodInfo[] = [ + 'label' => 'Google Pay', + 'iconUrl' => BeaconCommon::AssetURI('paymethod_google.svg'), + ]; + $paymentMethodInfo[] = [ + 'label' => 'Mastercard', + 'iconUrl' => BeaconCommon::AssetURI('paymethod_mastercard.svg'), + ]; + $paymentMethodInfo[] = [ + 'label' => 'visa', + 'iconUrl' => BeaconCommon::AssetURI('paymethod_visa.svg'), + ]; + $paymentMethodInfo[] = [ + 'label' => 'American Express', + 'iconUrl' => BeaconCommon::AssetURI('paymethod_amex.svg'), + ]; + $paymentMethodInfo[] = [ + 'label' => 'Discover', + 'iconUrl' => BeaconCommon::AssetURI('paymethod_discover.svg'), + ]; + $paymentMethodInfo[] = [ + 'label' => 'Diner\'s Club', + 'iconUrl' => BeaconCommon::AssetURI('paymethod_dinersclub.svg'), + ]; + $paymentMethodInfo[] = [ + 'label' => 'JCB', + 'iconUrl' => BeaconCommon::AssetURI('paymethod_jcb.svg'), + ]; + } else { + $paymentMethodInfo[] = [ + 'label' => $paymentMethodRows->Field('label'), + 'iconUrl' => BeaconCommon::AssetURI('paymethod_' . $code . '.svg'), + ]; + } + $paymentMethodRows->MoveNext(); } $forceEmail = null;