Integracja metod płatności Stripe i PayPal w Ruby on Rails

Opublikowany: 2022-03-11

Kluczową funkcją dla dużych firm eCommerce, takich jak AliExpress, Ebay i Amazon, jest bezpieczny sposób obsługi płatności, który jest niezbędny dla ich działalności. Jeśli ta funkcja zawiedzie, konsekwencje będą druzgocące. Dotyczy to liderów branży i programistów Ruby on Rails pracujących nad aplikacjami eCommerce.

Cyberbezpieczeństwo ma kluczowe znaczenie dla zapobiegania atakom, a sposobem na zwiększenie bezpieczeństwa procesu transakcji jest zwrócenie się do usługi zewnętrznej o jej obsługę. Sposobem na osiągnięcie tego celu jest włączenie bramek płatności do Twojej aplikacji, ponieważ zapewniają one autoryzację użytkownika, szyfrowanie danych i pulpit nawigacyjny, dzięki czemu możesz śledzić status transakcji w locie.

W sieci istnieje wiele usług bramek płatności, ale w tym artykule skupię się na integracji Stripe i PayPal z aplikacją Rails. Aby wymienić kilka innych: Amazon Payments, Square, SecurePay, WorldPay, Authorize.Net, 2Checkout.com, Braintree, Amazon czy BlueSnap.

Jak działa integracja bramki płatności

Reprezentacja ogólna dla transakcji dotyczących bramek płatniczych
Reprezentacja ogólna dla transakcji dotyczących bramek płatniczych

Ogólnie rzecz biorąc, w aplikacji będzie formularz/przycisk, w którym użytkownik może się zalogować/wstawić dane karty kredytowej. PayPal i Stripe już czynią ten pierwszy krok bezpieczniejszym, używając formularzy iframe lub popups , które uniemożliwiają Twojej aplikacji przechowywanie poufnych informacji o karcie kredytowej użytkownika, ponieważ zwrócą token reprezentujący tę transakcję. Niektórzy użytkownicy mogą już czuć się pewniej w przetwarzaniu płatności, wiedząc, że proces transakcji obsługuje usługa zewnętrzna, więc może to być również atrakcją dla Twojej aplikacji.

Po uwierzytelnieniu danych użytkownika, bramka płatnicza potwierdzi płatność kontaktując się z procesorem płatności, który komunikuje się z bankami w celu rozliczenia płatności. Zapewnia to prawidłowe obciążenie/uznanie transakcji.

Stripe używa formularza karty kredytowej z pytaniem o numer karty kredytowej, cvv i datę ważności. Więc użytkownik musi wypełnić dane karty kredytowej w zabezpieczonych wejściach Stripe. Po podaniu tych informacji zaplecze Twojej aplikacji przetwarza tę płatność za pomocą tokena.

W przeciwieństwie do Stripe, PayPal przekierowuje użytkownika do strony logowania PayPal. Użytkownik autoryzuje i wybiera metodę płatności za pośrednictwem PayPal, a Twój backend będzie obsługiwał tokeny zamiast poufnych danych użytkownika.

Ważne jest, aby wspomnieć, że w przypadku tych dwóch bramek płatniczych, Twój backend powinien poprosić o kontynuację realizacji transakcji przez API Stripe lub PayPal, które dadzą odpowiedź OK/NOK, więc Twoja aplikacja powinna odpowiednio przekierować użytkownika do strony pomyślnej lub błędu.

Celem tego artykułu jest dostarczenie krótkiego przewodnika po integracji tych dwóch bramek płatności w jednej aplikacji. We wszystkich testach będziemy używać piaskownic i kont testowych dostarczonych przez Stripe i PayPal w celu symulacji płatności.

Organizować coś

Przed integracją bramek płatności wykonamy konfigurację inicjalizacji aplikacji poprzez dodanie klejnotów, tabel bazy danych i strony indeksu. Ten projekt został stworzony przy użyciu Railsów w wersji 5.2.3 i Ruby 2.6.3.

Uwaga: Możesz sprawdzić nowe funkcje Rails 6 w naszym ostatnim artykule.

Krok 1: Zainicjuj aplikację Railsową.

Zainicjuj projekt, uruchamiając inicjalizację projektu za pomocą polecenia rails z nazwą aplikacji:

 rails new YOUR_APP_NAME

I cd w folderze aplikacji.

Krok 2: Zainstaluj klejnoty.

Oprócz klejnotów Stripe i PayPal, dodano kilka innych klejnotów:

  • devise : używane do uwierzytelniania i autoryzacji użytkownika
  • haml : narzędzie do tworzenia szablonów do renderowania stron użytkownika
  • jquery-rails : dla jquery w skryptach front-end
  • money-rails : do wyświetlania sformatowanych wartości pieniężnych

Dodaj do swojego Gemfile :

 gem "devise", ">= 4.7.1" gem "haml" gem "jquery-rails" gem "money-rails"

Po dodaniu uruchom w swoim CLI:

 bundle install

Krok 3: Zainicjuj klejnoty.

Niektóre z tych klejnotów będą wymagały inicjalizacji oprócz zainstalowania ich za pomocą bundle .

Instalacja urządzenia:

 rails g devise:install

Inicjalizacja money-rails :

 rails g money_rails:initializer

Zainicjuj jquery-rails , dołączając na dole app/assets/javascripts/application.js następujące:

 //= require jquery //= require jquery_ujs

Krok 4: Tabele i migracje

W projekcie zostaną użyte trzy tabele Użytkownicy , Produkty i Zamówienia .

  • Users : będą generowane przez devise
  • Kolumny Products :
    • name
    • price_cents
    • Stripe_plan_name : Identyfikator reprezentujący plan subskrypcji utworzony w Stripe, dzięki czemu użytkownicy mogą go subskrybować. To pole jest wymagane tylko w przypadku produktów powiązanych z planem Stripe.
    • paypal_plan_name : To samo co stripe_plan_name , ale dla PayPal
  • Kolumny Orders :
    • product_id
    • user_id
    • status : Poinformuje Cię, czy zamówienie jest w toku, nie powiodło się, czy zostało opłacone.
    • token : To token wygenerowany z interfejsów API (Stripe lub PayPal) w celu zainicjowania transakcji.
    • price_cents : Podobny do produktu, ale używany, aby ta wartość była trwała w rekordzie zamówienia
    • payment_gateway : Przechowuje bramkę płatności używaną do zamówienia PayPal lub Stripe
    • customer_id : Będzie używany dla Stripe w celu przechowywania klienta Stripe dla subskrypcji i zostanie to wyjaśnione bardziej szczegółowo w dalszej części.

Aby wygenerować te tabele, należy wygenerować kilka migracji:

Do tworzenia tabeli Użytkownicy . Biegać:

 rails g devise User

Do tworzenia tabeli Produkty . Wygeneruj migrację, uruchamiając:

 rails generate migration CreateProducts name:string stripe_plan_name:string paypal_plan_name:string

Otwórz utworzony plik migracji, który powinien znajdować się w db/migrate/ i wprowadź zmiany, aby migracja wyglądała podobnie do tego:

 class CreateProducts < ActiveRecord::Migration[5.2] def change create_table :products do |t| t.string :name t.string :stripe_plan_name t.string :paypal_plan_name end add_money :products, :price, currency: { present: true } end end

Do tworzenia tabeli Zamówienia . Wygeneruj migrację, uruchamiając:

 rails generate migration CreateOrders product_id:integer user_id:integer status:integer token:string charge_id:string error_message:string customer_id:string payment_gateway:integer

Ponownie otwórz utworzony plik migracji, który powinien znajdować się w db/migrate/ i wprowadź zmiany w tym pliku, aby wyglądał podobnie do tego:

 class CreateOrders < ActiveRecord::Migration[5.2] def change create_table :orders do |t| t.integer :product_id t.integer :user_id t.integer :status, default: 0 t.string :token t.string :charge_id t.string :error_message t.string :customer_id t.integer :payment_gateway t.timestamps end add_money :orders, :price, currency: { present: false } end end

Uruchom migracje baz danych, wykonując:

 rails db:migrate

Krok 5: Utwórz modele.

Model użytkownika jest już utworzony z instalacji devise i nie będą na nim wymagane żadne zmiany. Oprócz tego powstaną dwa modele dla Produktu i Zamówienia .

Produkt. Dodaj nowy plik app/models/product.rb z:

 class Product < ActiveRecord::Base monetize :price_cents has_many :orders end

Zamówienie. Dodaj nowy plik app/models/order.rb z:

 class Order < ApplicationRecord enum status: { pending: 0, failed: 1, paid: 2, paypal_executed: 3} enum payment_gateway: { stripe: 0, paypal: 1 } belongs_to :product belongs_to :user scope :recently_created, -> { where(created_at: 1.minutes.ago..DateTime.now) } def set_paid self.status = Order.statuses[:paid] end def set_failed self.status = Order.statuses[:failed] end def set_paypal_executed self.status = Order.statuses[:paypal_executed] end end

Krok 6: Wypełnij bazę danych.

W konsoli zostanie utworzony użytkownik i dwa produkty. Rekordy zamówień zostaną utworzone zgodnie z testami płatności.

  • rails s
  • W przeglądarce odwiedź http://localhost:3000
  • Zostaniesz przekierowany na stronę rejestracji.
  • Zarejestruj użytkownika, wpisując jego adres e-mail i hasło.
  • W Twoim terminalu zostaną wyświetlone następujące logi pokazujące, że użytkownik został utworzony w Twojej bazie danych:
 User Create (0.1ms) INSERT INTO "users" ("email", "encrypted_password", "created_at", "updated_at") VALUES (?, ?, ?, ?) …
  • Utwórz dwa produkty bez subskrypcji, uruchamiając rails c i dodając:
    • Product.create(name: "Awesome T-Shirt", price_cents: 3000)
    • Product.create(name: "Awesome Sneakers", price_cents: 5000)

Krok 7: Utwórz stronę indeksu

Strona główna projektu zawiera wybór produktów do zakupów lub subskrypcji. Dodatkowo posiada również sekcję wyboru metody płatności (Stripe lub PayPal). Przycisk przesyłania jest również używany dla każdego typu bramki płatności, ponieważ w przypadku PayPal dodamy własny projekt przycisku za pośrednictwem jego biblioteki JavaScript.

Najpierw utwórz trasy dla index i submit je w config/routes.rb .

 Rails.application.routes.draw do devise_for :users get '/', to: 'orders#index' post '/orders/submit', to: 'orders#submit' end

Utwórz i dodaj index akcji i submit w aplikacji kontrolera zamówień app/controllers/orders_controller.rb . Akcja orders#index przechowuje dwie zmienne do wykorzystania w interfejsie użytkownika: @products_purchase , która zawiera listę produktów bez planów, oraz @products_subscription , która zawiera produkty z planami PayPal i Stripe.

 class OrdersController < ApplicationController before_action :authenticate_user! def index products = Product.all @products_purchase = products.where(stripe_plan_name:nil, paypal_plan_name:nil) @products_subscription = products - @products_purchase end def submit end end

Utwórz plik w app/views/orders/index.html.haml . Ten plik zawiera wszystkie dane wejściowe, które zamierzamy wysłać do naszego zaplecza za pomocą metody przesyłania, oraz interakcję z bramkami płatności i wyborem produktów. Oto kilka atrybutów nazwy wejściowej:

  • Orders[product_id] przechowuje identyfikator produktu.
  • Orders[payment_gateway] zawiera bramkę płatności z wartościami Stripe lub PayPal dla drugiej strony.
 %div %h1 List of products = form_tag({:controller => "orders", :action => "submit" }, {:id => 'order-details'}) do %input{id:'order-type', :type=>"hidden", :value=>"stripe", :name=>'orders[payment_gateway]'} .form_row %h4 Charges/Payments - @products_purchase.each do |product| %div{'data-charges-and-payments-section': true} = radio_button_tag 'orders[product_id]', product.id, @products_purchase.first == product %span{id: "radioButtonName#{product.id}"} #{product.name} %span{id: "radioButtonPrice#{product.id}", :'data-price' => "#{product.price_cents}"} #{humanized_money_with_symbol product.price} %br %h4 Subscriptions - @products_subscription.each do |product| %div = radio_button_tag 'orders[product_id]', product.id, false %span{id: "radioButtonName#{product.id}"} #{product.name} %span{id: "radioButtonPrice#{product.id}", :'data-price' => "#{product.price_cents}"} #{humanized_money_with_symbol product.price} %br %hr %h1 Payment Method .form_row %div = radio_button_tag 'payment-selection', 'stripe', true, onclick: "changeTab();" %span Stripe %br %div = radio_button_tag 'payment-selection', 'paypal', false, onclick: "changeTab();" %span Paypal %br %br %div{id:'tab-stripe', class:'paymentSelectionTab active'} %div{id:'card-element'} %div{id:'card-errors', role:"alert"} %br %br = submit_tag "Buy it!", id: "submit-stripe" %div{id:'tab-paypal', class:'paymentSelectionTab'} %div{id: "submit-paypal"} %br %br %hr :javascript function changeTab() { var newActiveTabID = $('input[name="payment-selection"]:checked').val(); $('.paymentSelectionTab').removeClass('active'); $('#tab-' + newActiveTabID).addClass('active'); } :css #card-element { width:500px; } .paymentSelectionTab { display: none; } .paymentSelectionTab.active { display: block !important; }

Jeśli uruchamiasz swoją aplikację z rails s i odwiedź swoją stronę w http://localhost:3000 . Powinieneś widzieć stronę w następujący sposób:

Surowa strona indeksu bez integracji Stripe i PayPal
Surowa strona indeksu bez integracji Stripe i PayPal

Przechowywanie poświadczeń bramki płatności

Klucze PayPal i Stripe będą przechowywane w pliku, który nie jest śledzony przez Git. W tym pliku przechowywane są dwa rodzaje kluczy dla każdej bramki płatności i na razie będziemy używać dla nich wartości fikcyjnej. Dodatkowe wskazówki dotyczące tworzenia tych kluczy przedstawiono w dalszych rozdziałach.

Krok 1: Dodaj to w .gitignore .

 /config/application.yml

Krok 2: Utwórz plik ze swoimi poświadczeniami w config/application.yml . Powinien zawierać wszystkie klucze piaskownicy/testu PayPal i Stripe umożliwiające dostęp do tych interfejsów API.

 test: &default PAYPAL_ENV: sandbox PAYPAL_CLIENT_ID: YOUR_CREDENTIAL_HERE PAYPAL_CLIENT_SECRET: YOUR_CREDENTIAL_HERE STRIPE_PUBLISHABLE_KEY: YOUR_CREDENTIAL_HERE STRIPE_SECRET_KEY: YOUR_CREDENTIAL_HERE development: <<: *default

Krok 3: Aby przechowywać zmienne z pliku config/application.yml podczas uruchamiania aplikacji, dodaj te wiersze w config/application.rb wewnątrz klasy Application , aby były dostępne w ENV .

 config_file = Rails.application.config_for(:application) config_file.each do |key,value| ENV[key] = value end unless config_file.nil?

Konfiguracja pasków

Dodamy klejnot do korzystania z API Stripe: stripe-rails . Utworzenie konta Stripe jest również wymagane, aby można było przetwarzać opłaty i subskrypcje. Jeśli musisz, możesz zapoznać się z metodami API dla Stripe API w oficjalnej dokumentacji.

Krok 1: Dodaj klejnot w paski do swojego projektu.

Gem stripe-rails zapewni interfejs dla wszystkich żądań API używanych w tym projekcie.

Dodaj to w Gemfile :

 gem 'stripe-rails'

Biegać:

 bundle install

Krok 2: Wygeneruj klucze API.

Aby mieć klucze API do komunikacji ze Stripe, musisz utworzyć konto w Stripe. Aby przetestować aplikację, można skorzystać z trybu testowego, więc w procesie tworzenia konta Stripe nie trzeba podawać żadnych prawdziwych informacji biznesowych.

  • Utwórz konto w Stripe, jeśli go nie masz (https://dashboard.stripe.com/).
  • Pozostając w panelu Stripe, po zalogowaniu włącz opcję Wyświetl dane testowe .
  • Na stronie https://dashboard.stripe.com/test/apikeys zastąp YOUR_CREDENTIAL_HERE wartości STRIPE_PUBLISHABLE_KEY i STRIPE_SECRET_KEY w /config/application.yml treścią z Publishable Key i Secret key .

Krok 3: Zainicjuj moduł Stripe

Oprócz wymiany kluczy, musimy jeszcze zainicjować moduł Stripe, aby korzystał z kluczy już ustawionych w naszym ENV .

Utwórz plik w config/initializers/stripe.rb z:

 Rails.application.configure do config.stripe.secret_key = ENV["STRIPE_SECRET_KEY"] config.stripe.publishable_key = ENV["STRIPE_PUBLISHABLE_KEY"] end

Krok 4: Zintegruj Stripe z przodu.

Dodamy bibliotekę Stripe JavaScript i logikę wysyłania tokena, który reprezentuje informacje o karcie kredytowej użytkownika i będzie przetwarzany w naszym zapleczu.

W pliku index.html.haml dodaj to na początku pliku. Spowoduje to użycie modułu Stripe (dostarczonego przez gem), aby dodać bibliotekę JavaScript Stripe do strony użytkownika.

 = stripe_javascript_tag

Stripe używa bezpiecznych pól wejściowych, które są tworzone za pomocą ich API. Ponieważ są one tworzone w iframe utworzonej za pomocą tego interfejsu API, nie musisz się martwić możliwymi lukami w obsłudze informacji o karcie kredytowej użytkownika. Ponadto Twój backend nie będzie w stanie przetwarzać ani przechowywać żadnych poufnych danych użytkownika i otrzyma tylko token reprezentujący te informacje.

Te pola wejściowe są tworzone przez wywołanie stripe.elements().create('card') . Następnie wystarczy wywołać zwrócony obiekt za pomocą mount() , przekazując jako argument element HTML id/class, do którego te dane wejściowe powinny być podłączone. Więcej informacji można znaleźć w Stripe.

Gdy użytkownik naciśnie przycisk przesyłania metodą płatności Stripe, na utworzonym elemencie karty Stripe wykonywane jest kolejne wywołanie API zwracając obietnicę:

 stripe.createToken(card).then(function(result)

Zmienna result tej funkcji, jeśli nie ma przypisanego błędu właściwości, będzie miała token, który można pobrać, uzyskując dostęp do atrybutu result.token.id . Ten token zostanie wysłany na zaplecze.

Aby wprowadzić te zmiany, zastąp komentowany kod // YOUR STRIPE AND PAYPAL CODE WILL BE HERE w index.html.haml na:

 (function setupStripe() { //Initialize stripe with publishable key var stripe = Stripe("#{ENV['STRIPE_PUBLISHABLE_KEY']}"); //Create Stripe credit card elements. var elements = stripe.elements(); var card = elements.create('card'); //Add a listener in order to check if card.addEventListener('change', function(event) { //the div card-errors contains error details if any var displayError = document.getElementById('card-errors'); document.getElementById('submit-stripe').disabled = false; if (event.error) { // Display error displayError.textContent = event.error.message; } else { // Clear error displayError.textContent = ''; } }); // Mount Stripe card element in the #card-element div. card.mount('#card-element'); var form = document.getElementById('order-details'); // This will be called when the #submit-stripe button is clicked by the user. form.addEventListener('submit', function(event) { $('#submit-stripe').prop('disabled', true); event.preventDefault(); stripe.createToken(card).then(function(result) { if (result.error) { // Inform that there was an error. var errorElement = document.getElementById('card-errors'); errorElement.textContent = result.error.message; } else { // Now we submit the form. We also add a hidden input storing // the token. So our back-end can consume it. var $form = $("#order-details"); // Add a hidden input orders[token] $form.append($('<input type="hidden" name="orders[token]"/>').val(result.token.id)); // Set order type $('#order-type').val('stripe'); $form.submit(); } }); return false; }); }()); //YOUR PAYPAL CODE WILL BE HERE

Jeśli odwiedzasz swoją stronę, powinna ona wyglądać następująco z nowymi bezpiecznymi polami wejściowymi Stripe:

Strona indeksu zintegrowana z bezpiecznymi polami wprowadzania Stripe.
Strona indeksu zintegrowana z bezpiecznymi polami wprowadzania Stripe.

Krok 5: Przetestuj swoją aplikację.

Wypełnij formularz karty kredytowej kartą testową (https://stripe.com/docs/testing) i prześlij stronę. Sprawdź, czy akcja submit jest wywoływana ze wszystkimi parametrami ( product_id , payment_gateway i token ) w danych wyjściowych serwera.

Opłaty za paski

Opłaty Stripe to jednorazowe transakcje. Dlatego po transakcji opłaty Stripe otrzymasz pieniądze bezpośrednio od klienta. Jest to idealne rozwiązanie do sprzedaży produktów niezwiązanych z planami. W dalszej części pokażę, jak wykonać ten sam typ transakcji w systemie PayPal, ale nazwa PayPal dla tego typu transakcji to Płatność .

W tym dziale podam również cały szkielet do obsługi i złożenia zamówienia. Zamówienie tworzymy w akcji submit po przesłaniu formularza Stripe. To zamówienie będzie początkowo miało status Oczekujące , więc jeśli coś pójdzie nie tak podczas przetwarzania tego zamówienia, nadal będzie ono Oczekujące .

Jeśli jakikolwiek błąd wyniknie z wywołań Stripe API, ustawiamy zamówienie w stanie niepowodzenia , a jeśli opłata zostanie zakończona pomyślnie, będzie w stanie opłaconym . Użytkownik jest również przekierowywany zgodnie z odpowiedzią Stripe API, jak pokazano na poniższym wykresie:

Transakcje w paski.
Transakcje w paski.

Dodatkowo, gdy wykonywana jest opłata Stripe, zwracany jest identyfikator. Będziemy przechowywać ten identyfikator, abyś w razie potrzeby mógł go później wyszukać na pulpicie nawigacyjnym Stripe. Ten identyfikator może być również użyty, jeśli zamówienie musi zostać zwrócone. Taka rzecz nie zostanie omówiona w tym artykule.

Krok 1: Utwórz usługę Stripe.

Będziemy używać klasy singleton do reprezentowania operacji Stripe za pomocą interfejsu API Stripe. W celu utworzenia opłaty wywoływana jest metoda Stripe::Charge.create , a zwrócony atrybut ID obiektu zostanie zapisany w rekordzie zamówienia charge_id . Ta funkcja create jest wywoływana przez przekazanie tokena pochodzącego z front-endu, ceny zamówienia i opisu.

Utwórz więc nowy folder app/services/orders i dodaj usługę Stripe: app/services/orders/stripe.rb zawierającą klasę singleton Orders::Stripe , która ma wpis w metodzie execute .

 class Orders::Stripe INVALID_STRIPE_OPERATION = 'Invalid Stripe Operation' def self.execute(order:, user:) product = order.product # Check if the order is a plan if product.stripe_plan_name.blank? charge = self.execute_charge(price_cents: product.price_cents, description: product.name, card_token: order.token) else #SUBSCRIPTIONS WILL BE HANDLED HERE end unless charge&.id.blank? # If there is a charge with id, set order paid. order.charge_id = charge.id order.set_paid end rescue Stripe::StripeError => e # If a Stripe error is raised from the API, # set status failed and an error message order.error_message = INVALID_STRIPE_OPERATION order.set_failed end private def self.execute_charge(price_cents:, description:, card_token:) Stripe::Charge.create({ amount: price_cents.to_s, currency: "usd", description: description, source: card_token }) end end

Krok 2: Zaimplementuj akcję przesyłania i wywołaj usługę Stripe.

W orders_controller.rb , dodaj następujące w akcji submit , która w zasadzie wywoła usługę Orders::Stripe.execute . Zauważ, że dodano również dwie nowe prywatne funkcje: prepare_new_order i order_params .

 def submit @order = nil #Check which type of order it is if order_params[:payment_gateway] == "stripe" prepare_new_order Orders::Stripe.execute(order: @order, user: current_user) elsif order_params[:payment_gateway] == "paypal" #PAYPAL WILL BE HANDLED HERE end ensure if @order&.save if @order.paid? # Success is rendered when order is paid and saved return render html: SUCCESS_MESSAGE elsif @order.failed? && [email protected]_message.blank? # Render error only if order failed and there is an error_message return render html: @order.error_message end end render html: FAILURE_MESSAGE end private # Initialize a new order and and set its user, product and price. def prepare_new_order @order = Order.new(order_params) @order.user_id = current_user.id @product = Product.find(@order.product_id) @order.price_cents = @product.price_cents end def order_params params.require(:orders).permit(:product_id, :token, :payment_gateway, :charge_id) end

Krok 3: Przetestuj swoją aplikację.

Sprawdź, czy akcja submit, wywołana z ważną kartą testową, powoduje przekierowanie do pomyślnej wiadomości. Dodatkowo sprawdź w swoim panelu Stripe, czy zamówienie jest również wyświetlane.

Subskrypcje w paski

Subskrypcje lub plany można tworzyć dla płatności cyklicznych. Przy tego typu produktach użytkownik jest rozliczany automatycznie w trybie dziennym, tygodniowym, miesięcznym lub rocznym, zgodnie z konfiguracją planu. W tej sekcji użyjemy pola dla produktu stripe_plan_name w celu przechowywania identyfikatora planu — właściwie możemy wybrać identyfikator i nazwiemy go premium-plan który będzie używany do tworzenia planu relacja customer <-> subscription .

Stworzymy również nową kolumnę dla tabeli użytkowników o nazwie stripe_customer_id , która zostanie wypełniona właściwością id obiektu klienta Stripe. Klient Stripe jest tworzony po wywołaniu funkcji Stripe::Customer.create i możesz również sprawdzić klientów utworzonych i połączonych z Twoim kontem w (https://dashboard.stripe.com/test/customers). Klientów tworzymy poprzez przekazanie parametru source , który w naszym przypadku jest tokenem wygenerowanym w interfejsie użytkownika, który jest wysyłany po przesłaniu formularza.

Obiekt klienta uzyskany z ostatniego wspomnianego wywołania API Stripe jest również używany do tworzenia subskrypcji, co odbywa się poprzez wywołanie customer.subscriptions.create i przekazanie identyfikatora planu jako parametru.

Dodatkowo, klejnot stripe-rails zapewnia interfejs do pobierania i aktualizowania klienta ze Stripe, co odbywa się poprzez wywołanie odpowiednio Stripe::Customer.retrieve i Stripe::Customer.update .

Tak więc, jeśli rekord użytkownika ma już stripe_customer_id , zamiast tworzyć nowego klienta za pomocą Stripe::Customer.create , wywołamy Stripe::Customer.retrieve przekazując stripe_customer_id jako parametr, a następnie Stripe::Customer.update , aw tym przypadku przekazanie tokenowi parametru.

Najpierw stworzymy plan za pomocą Stripe API, abyśmy mogli stworzyć nowy produkt subskrypcji za pomocą pola stripe_plan_name . Następnie dokonamy modyfikacji w orders_controller i usłudze Stripe, aby obsłużono tworzenie i wykonywanie subskrypcji Stripe.

Krok 1: Utwórz plan za pomocą Stripe API.

Otwórz konsolę za pomocą rails c . Utwórz subskrypcję dla swojego konta Stripe za pomocą:

 Stripe::Plan.create({ amount: 10000, interval: 'month', product: { name: 'Premium plan', }, currency: 'usd', id: 'premium-plan', })

Jeśli zwrócony wynik w tym kroku jest prawdziwy, oznacza to, że plan został pomyślnie utworzony i możesz uzyskać do niego dostęp na pulpicie nawigacyjnym Stripe.

Krok 2: Utwórz produkt w bazie danych z ustawionym polem stripe_plan_name .

Teraz utwórz produkt z stripe_plan_name ustawionym jako premium-plan w bazie danych:

 Product.create(price_cents: 10000, name: 'Premium Plan', stripe_plan_name: 'premium-plan')

Krok 3: Wygeneruj migrację, aby dodać kolumnę stripe_customer_id w tabeli users .

Uruchom w terminalu:

 rails generate migration AddStripeCustomerIdToUser stripe_customer_id:string rails db:migrate

Krok 4: Zaimplementuj logikę subskrypcji w klasie usługi Stripe.

Dodaj jeszcze dwie funkcje w prywatnych metodach app/services/orders/stripe.rb : execute_subscription odpowiada za tworzenie subskrypcji w obiekcie klienta. Funkcja find_or_create_customer odpowiada za zwrócenie już utworzonego klienta lub poprzez zwrócenie nowo utworzonego klienta.

 def self.execute_subscription(plan:, token:, customer:) customer.subscriptions.create({ plan: plan }) end def self.find_or_create_customer(card_token:, customer_id:, email:) if customer_id stripe_customer = Stripe::Customer.retrieve({ id: customer_id }) if stripe_customer stripe_customer = Stripe::Customer.update(stripe_customer.id, { source: card_token}) end else stripe_customer = Stripe::Customer.create({ email: email, source: card_token }) end stripe_customer end

Na koniec, w funkcji execute w tym samym pliku ( app/services/orders/stripe.rb ), najpierw find_or_create_customer , a następnie wykonamy subskrypcję, wywołując execute_subscription , przekazując poprzednio pobranego/utworzonego klienta. Zastąp więc komentarz #SUBSCRIPTIONS WILL BE HANDLED HERE w metodzie execute następującym kodem:

 customer = self.find_or_create_customer(card_token: order.token, customer_id: user.stripe_customer_id, email: user.email) if customer user.update(stripe_customer_id: customer.id) order.customer_id = customer.id charge = self.execute_subscription(plan: product.stripe_plan_name, customer: customer)

Krok 5: Przetestuj swoją aplikację.

Wejdź na swoją stronę, wybierz subskrypcję produktu Premium Plan i wypełnij ważną kartę testową. Po przesłaniu powinien przekierować Cię do udanej strony. Dodatkowo sprawdź w swoim panelu Stripe, czy subskrypcja została pomyślnie utworzona.

Konfiguracja PayPal

Podobnie jak w Stripe, dodamy również klejnot do korzystania z API PayPal: paypal-sdk-rest , wymagane jest również utworzenie konta PayPal. Opisowy przepływ pracy dla PayPal korzystający z tego klejnotu można znaleźć w oficjalnej dokumentacji API PayPal.

Krok 1: Dodaj klejnot paypal-sdk-rest do swojego projektu.

Dodaj to w Gemfile :

 gem 'paypal-sdk-rest'

Biegać:

 bundle install

Krok 2: Wygeneruj klucze API.

Aby mieć klucze API do komunikacji z PayPal, musisz utworzyć konto PayPal. Więc:

  • Utwórz konto (lub użyj swojego konta PayPal) na https://developer.paypal.com/.
  • Nadal zalogowany na swoje konto, utwórz dwa konta sandbox na https://developer.paypal.com/developer/accounts/:
    • Osobiste (Konto Kupującego) — będzie używane w Twoich testach do dokonywania płatności i subskrypcji.
    • Biznesowe (konto sprzedawcy) – zostanie połączone z aplikacją, która będzie miała klucze API, których szukamy. Poza tym wszystkie transakcje można śledzić na tym koncie.
  • Utwórz aplikację pod adresem https://developer.paypal.com/developer/applications, korzystając z poprzedniego biznesowego konta piaskownicy.
  • Po tym kroku otrzymasz dwa klucze do PayPal: Client ID i Secret .
  • W pliku config/application.yml zastąp YOUR_CREDENTIAL_HERE z PAYPAL_CLIENT_ID i PAYPAL_CLIENT_SECRET kluczami, które właśnie otrzymałeś.

Krok 3: Zainicjuj moduł PayPal.

Podobnie jak w Stripe, oprócz wymiany kluczy w application.yml , nadal musimy zainicjować moduł PayPal, aby mógł używać kluczy już ustawionych w naszej zmiennej ENV . W tym celu utwórz plik w config/initializers/paypal.rb z:

 PayPal::SDK.configure( mode: ENV['PAYPAL_ENV'], client_id: ENV['PAYPAL_CLIENT_ID'], client_secret: ENV['PAYPAL_CLIENT_SECRET'], ) PayPal::SDK.logger.level = Logger::INFO

Krok 4: Zintegruj PayPal z frontendem.

W index.html.haml dodaj to na początku pliku:

 %script(src="https://www.paypal.com/sdk/js?client-id=#{ENV['PAYPAL_CLIENT_ID']}")

W przeciwieństwie do Stripe, PayPal używa tylko przycisku, który po kliknięciu otwiera bezpieczne wyskakujące okienko, w którym użytkownik może się zalogować i przejść do płatności/subskrypcji. Ten przycisk można wyświetlić, wywołując metodę paypal.Button(PARAM1).render(PARAM2) .

  • PARAM1 to obiekt z konfiguracją środowiska i dwiema funkcjami zwrotnymi jako właściwościami: createOrder i onApprove .
  • PARAM2 wskazuje identyfikator elementu HTML, do którego należy dołączyć przycisk PayPal.

Tak więc, nadal w tym samym pliku, zamień komentowany kod YOUR PAYPAL CODE WILL BE HERE na:

 (function setupPaypal() { function isPayment() { return $('[data-charges-and-payments-section] input[name="orders[product_id]"]:checked').length } function submitOrderPaypal(chargeID) { var $form = $("#order-details"); // Add a hidden input orders[charge_id] $form.append($('<input type="hidden" name="orders[charge_id]"/>').val(chargeID)); // Set order type $('#order-type').val('paypal'); $form.submit(); } paypal.Buttons({ env: "#{ENV['PAYPAL_ENV']}", createOrder: function() { }, onApprove: function(data) { } }).render('#submit-paypal'); }());

Krok 5: Przetestuj swoją aplikację.

Odwiedź swoją stronę i sprawdź, czy przycisk PayPal jest renderowany po wybraniu PayPal jako metody płatności.

Transakcje PayPal

Logika transakcji PayPal, w przeciwieństwie do Stripe, jest nieco bardziej złożona, ponieważ obejmuje więcej żądań pochodzących z frontendu do backendu. Dlatego ta sekcja istnieje. Wyjaśnię mniej więcej (bez żadnego kodu) jak zostaną zaimplementowane funkcje opisane w createOrder i onApprove oraz czego oczekuje się od procesów back-endowych.

Krok 1: Gdy użytkownik kliknie przycisk przesyłania PayPal, wyskakujące okienko PayPal z prośbą o podanie danych uwierzytelniających jest otwarte, ale jest w stanie ładowania. Wywoływana jest funkcja callback createOrder .

Wyskakujące okienko PayPal, stan ładowania
Wyskakujące okienko PayPal, stan ładowania

Krok 2: W tej funkcji wykonamy żądanie do naszego zaplecza, które utworzy płatność/subskrypcję. To jest sam początek transakcji i żadne opłaty nie zostaną jeszcze naliczone, więc transakcja jest w rzeczywistości w stanie oczekiwania . Nasz backend powinien zwrócić nam token, który zostanie wygenerowany za pomocą modułu PayPal (dostarczonego przez gem paypal-rest-sdk ).

Krok 3: Nadal w wywołaniu zwrotnym createOrder zwracamy ten token wygenerowany na naszym zapleczu i jeśli wszystko jest w porządku, wyskakujące okienko PayPal wyświetli następujące informacje z prośbą o dane uwierzytelniające użytkownika:

Wyskakujące okienko PayPal, poświadczenia użytkownika
Wyskakujące okienko PayPal, poświadczenia użytkownika

Krok 4: Po zalogowaniu się użytkownika i wybraniu metody płatności, wyskakujące okienko zmieni swój stan na następujący:

Wyskakujące okienko PayPal, autoryzowana transakcja
Wyskakujące okienko PayPal, autoryzowana transakcja

Krok 5: Wywołanie zwrotne funkcji onApprove zostało wywołane. Zdefiniowaliśmy to w następujący sposób: onApprove: function(data) . Obiekt data będzie posiadał informacje o płatności w celu jego realizacji. W tym wywołaniu zwrotnym zostanie wykonane kolejne żądanie do naszej funkcji zaplecza, tym razem przekazując obiekt danych w celu realizacji zamówienia PayPal.

Krok 6: Nasz backend wykonuje tę transakcję i zwraca 200 (jeśli się powiedzie).

Krok 7: Kiedy nasz backend wróci, przesyłamy formularz. To już trzecia prośba, którą kierujemy do naszego zaplecza.

Zwróć uwagę, że w przeciwieństwie do Stripe, w tym procesie do naszego zaplecza wysyłane są trzy żądania. I będziemy odpowiednio synchronizować status naszego rekordu zamówienia:

  • wywołanie zwrotne createOrder : tworzona jest transakcja i tworzony jest również rekord zamówienia; dlatego domyślnie znajduje się w stanie oczekiwania .
  • Callback onApprove : Transakcja zostanie wykonana, a nasze zamówienie zostanie ustawione jako paypal_executed .
  • Strona zamówienia została przesłana: Transakcja została już wykonana, więc nic się nie zmienia. Rekord zamówienia zmieni swój stan na opłacone .

Cały ten proces opisuje poniższy wykres:

Transakcje PayPal
Transakcje PayPal

Płatności PayPal

Płatności PayPal działają zgodnie z tą samą logiką, co opłaty Stripe, więc reprezentują transakcje jednorazowe, ale jak wspomniano w poprzedniej sekcji, mają inną logikę przepływu. Oto zmiany, które trzeba będzie wprowadzić do obsługi płatności PayPal:

Krok 1: Utwórz nowe trasy dla PayPal i realizuj płatności.

Add the following routes in config/routes.rb :

 post 'orders/paypal/create_payment' => 'orders#paypal_create_payment', as: :paypal_create_payment post 'orders/paypal/execute_payment' => 'orders#paypal_execute_payment', as: :paypal_execute_payment

This will create two new routes for creating and executing payments which will be handled in the paypal_create_payment and paypal_execute_payment orders controller methods.

Step 2: Create the PayPal service.

Add the singleton class Orders::Paypal at: app/services/orders/paypal.rb .

This service will initially have three responsibilities:

  • The create_payment method creates a payment by calling PayPal::SDK::REST::Payment.new . A token is generated and returned to the front-end.
  • The execute_payment method executes the payment by first finding the previous created payment object through PayPal::SDK::REST::Payment.find(payment_id) which uses the payment_id as an argument which has the same value as the charge_id stored in the previous step in the order object. After that, we call execute in the payment object with a given payer as the parameter. This payer is given by the front end after the user has provided credentials and selected a payment method in the popup.
  • The finish method finds an order by a specific charge_id querying for recently created orders in the paypal_executed state. If a record is found, it is marked as paid.
 class Orders::Paypal def self.finish(charge_id) order = Order.paypal_executed.recently_created.find_by(charge_id: charge_id) return nil if order.nil? order.set_paid order end def self.create_payment(order:, product:) payment_price = (product.price_cents/100.0).to_s currency = "USD" payment = PayPal::SDK::REST::Payment.new({ intent: "sale", payer: { payment_method: "paypal" }, redirect_urls: { return_url: "/", cancel_url: "/" }, transactions: [{ item_list: { items: [{ name: product.name, sku: product.name, price: payment_price, currency: currency, quantity: 1 } ] }, amount: { total: payment_price, currency: currency }, description: "Payment for: #{product.name}" }] }) if payment.create order.token = payment.token order.charge_id = payment.id return payment.token if order.save end end def self.execute_payment(payment_id:, payer_id:) order = Order.recently_created.find_by(charge_id: payment_id) return false unless order payment = PayPal::SDK::REST::Payment.find(payment_id) if payment.execute( payer_id: payer_id ) order.set_paypal_executed return order.save end end

Step 3: Call the PayPal service in the controller in the submit action.

Add a callback for prepare_new_order before the action paypal_create_payment (which will be added in the next step) is requested by adding the following in the file app/controllers/orders_controller.rb :

 class OrdersController < ApplicationController before_action :authenticate_user! before_action :prepare_new_order, only: [:paypal_create_payment] ...

Again, in the same file, call PayPal service in the submit action by replacing the commented code #PAYPAL WILL BE HANDLED HERE. z następującymi:

 ... elsif order_params[:payment_gateway] == "paypal" @order = Orders::Paypal.finish(order_params[:token]) end ...

Step 4: Create the actions for handling requests.

Still, in the app/controllers/orders_controller.rb file, create two new actions (which should be public) for handling requests to paypal_create_payment and paypal_execute_payment routes:

  • The paypal_create_payment method: Will call our service method create_payment . If that returns successfully, it will return the order token created by Orders::Paypal.create_payment .
  • The paypal_execute_payment method: Will call our service method execute_payment (which executes our payments). If the payment is performed successfully, it returns 200.
 ... def paypal_create_payment result = Orders::Paypal.create_payment(order: @order, product: @product) if result render json: { token: result }, status: :ok else render json: {error: FAILURE_MESSAGE}, status: :unprocessable_entity end end def paypal_execute_payment if Orders::Paypal.execute_payment(payment_id: params[:paymentID], payer_id: params[:payerID]) render json: {}, status: :ok else render json: {error: FAILURE_MESSAGE}, status: :unprocessable_entity end end ...

Step 5: Implement the front-end callback functions for createOrder and onApprove .

Make your paypal.Button.render call look like this:

 paypal.Buttons({ env: "#{ENV['PAYPAL_ENV']}", createOrder: function() { $('#order-type').val("paypal"); if (isPayment()) { return $.post("#{paypal_create_payment_url}", $('#order-details').serialize()).then(function(data) { return data.token; }); } else { } }, onApprove: function(data) { if (isPayment()) { return $.post("#{paypal_execute_payment_url}", { paymentID: data.paymentID, payerID: data.payerID }).then(function() { submitOrderPaypal(data.paymentID) }); } else { } } }).render('#submit-paypal');

As mentioned in the previous section, we call paypal_create_payment_url for the createOrder callback and paypal_execute_payment_url for the onApprove callback. Notice that if the last request returns success, we submit the order, which is the third request made to the server.

In the createOrder function handler, we return a token (obtained from the back end). In the onApprove callback, we have two properties passed down to our back-end paymentID and payerID . These will be used in order to execute the payment.

Finally, notice that we have two empty else clauses as I'm leaving room for the next section where we will be adding PayPal subscriptions.

If you visit your page after integrating the front-end JavaScript section and select PayPal as the payment method, it should look like the following:

Index page after integration with PayPal
Index page after integration with PayPal

Step 6: Test your application.

  • Odwiedź stronę indeksu.
  • Wybierz produkt płatności/obciążenia i PayPal jako metodę płatności.
  • Kliknij przycisk prześlij PayPal.
  • W wyskakującym okienku PayPal:
    • Użyj danych logowania do utworzonego konta kupującego.
    • Zaloguj się i potwierdź zamówienie.
    • Wyskakujące okienko powinno się zamknąć.
  • Sprawdź, czy zostałeś przekierowany na stronę sukcesu.
  • Na koniec sprawdź, czy zamówienie zostało zrealizowane na koncie PayPal, logując się na swoje konto firmowe na https://www.sandbox.paypal.com/signin i sprawdzając pulpit nawigacyjny https://www.sandbox.paypal.com/listing /transakcje.

Subskrypcje PayPal

Plany/umowy/subskrypcje PayPal działają zgodnie z tą samą logiką, co subskrypcje Stripe i są tworzone dla płatności cyklicznych. Przy tego typu produktach użytkownik jest obciążany codziennie, tygodniowo, miesięcznie lub rocznie automatycznie zgodnie z jego konfiguracją.

Użyjemy pola dla produktu paypal_plan_name , aby zapisać identyfikator planu podany przez PayPal. W tym przypadku inaczej niż w Stripe nie wybieramy identyfikatora, a PayPal zwraca tę wartość, do której zostanie zaktualizowany ostatnio utworzony produkt w naszej bazie danych.

Aby utworzyć subskrypcję, na żadnym etapie nie są wymagane żadne informacje o customer , ponieważ metoda onApprove prawdopodobnie obsługuje to powiązanie w swojej podstawowej implementacji. Więc nasze stoły pozostaną takie same.

Krok 1: Utwórz plan za pomocą API PayPal.

Otwórz konsolę za pomocą rails c . Utwórz subskrypcję swojego konta PayPal za pomocą:

 plan = PayPal::SDK::REST::Plan.new({ name: 'Premium Plan', description: 'Premium Plan', type: 'fixed', payment_definitions: [{ name: 'Premium Plan', type: 'REGULAR', frequency_interval: '1', frequency: 'MONTH', cycles: '12', amount: { currency: 'USD', value: '100.00' } }], merchant_preferences: { cancel_url: 'http://localhost:3000/', return_url: 'http://localhost:3000/', max_fail_attempts: '0', auto_bill_amount: 'YES', initial_fail_amount_action: 'CONTINUE' } }) plan.create plan_update = { op: 'replace', path: '/', value: { state: 'ACTIVE' } } plan.update(plan_update)

Krok 2: Zaktualizuj ostatni produkt w bazie danych paypal_plan_name o zwrócony plan.id .

Biegać:

 Product.last.update(paypal_plan_name: plan.id)

Krok 3: Dodaj trasy do subskrypcji PayPal.

Dodaj dwie nowe trasy w config/routes.rb :

 post 'orders/paypal/create_subscription' => 'orders#paypal_create_subscription', as: :paypal_create_subscription post 'orders/paypal/execute_subscription' => 'orders#paypal_execute_subscription', as: :paypal_execute_subscription

Krok 4: Obsługa tworzenia i wykonywania w usłudze PayPal.

Dodaj dwie dodatkowe funkcje do tworzenia i wykonywania subskrypcji w Orders::Paypal app/services/orders/paypal.rb :

 def self.create_subscription(order:, product:) agreement = PayPal::SDK::REST::Agreement.new({ name: product.name, description: "Subscription for: #{product.name}", start_date: (Time.now.utc + 1.minute).iso8601, payer: { payment_method: "paypal" }, plan: { id: product.paypal_plan_name } }) if agreement.create order.token = agreement.token return agreement.token if order.save end end def self.execute_subscription(token:) order = Order.recently_created.find_by(token: token) return false unless order agreement = PayPal::SDK::REST::Agreement.new agreement.token = token if agreement.execute order.charge_id = agreement.id order.set_paypal_executed return order.charge_id if order.save end end

W create_subscription , inicjujemy umowę, wywołując metodę PayPal::SDK::REST::Agreement.new i przekazując product.paypal_plan_name jako jeden z jej atrybutów. Następnie tworzymy go, a teraz dla tego ostatniego obiektu zostanie ustawiony token. Odkładamy również token na przód.

W execute_subscription , znajdujemy rekord order utworzony w poprzednim wywołaniu. Następnie inicjujemy nową umowę, ustawiamy token poprzedniego obiektu i wykonujemy go. Jeśli ten ostatni krok zostanie pomyślnie wykonany, status zamówienia zostanie ustawiony na paypal_executed . A teraz wracamy do interfejsu użytkownika identyfikatora umowy, który jest również przechowywany w order.chager_id .

Krok 5: Dodaj akcje do tworzenia i wykonywania subskrypcji w orders_controller .

Zmień app/controllers/orders_controller.rb . Na górze klasy, najpierw, a następnie zaktualizuj wywołanie zwrotne prepare_new_order , aby zostało wykonane również przed paypal_create_subscription :

 class OrdersController < ApplicationController before_action :authenticate_user! before_action :prepare_new_order, only: [:paypal_create_payment, :paypal_create_subscription]

Dodatkowo w tym samym pliku dodaj dwie funkcje publiczne tak, aby wywołały usługę Orders::Paypal o podobnym przepływie jak już mamy w płatnościach PayPal:

 ... def paypal_create_subscription result = Orders::Paypal.create_subscription(order: @order, product: @product) if result render json: { token: result }, status: :ok else render json: {error: FAILURE_MESSAGE}, status: :unprocessable_entity end end def paypal_execute_subscription result = Orders::Paypal.execute_subscription(token: params[:subscriptionToken]) if result render json: { id: result}, status: :ok else render json: {error: FAILURE_MESSAGE}, status: :unprocessable_entity end end ...

Krok 6: Dodanie modułów obsługi subskrypcji dla wywołań zwrotnych createOrder i onApprove w interfejsie użytkownika.

Na koniec, w index.html.haml , zastąp funkcję paypal.Buttons następującą, która wypełni dwie puste else , które mieliśmy wcześniej:

 paypal.Buttons({ env: "#{ENV['PAYPAL_ENV']}", createOrder: function() { $('#order-type').val("paypal"); if (isPayment()) { return $.post("#{paypal_create_payment_url}", $('#order-details').serialize()).then(function(data) { return data.token; }); } else { return $.post("#{paypal_create_subscription_url}", $('#order-details').serialize()).then(function(data) { return data.token; }); } }, onApprove: function(data) { if (isPayment()) { return $.post("#{paypal_execute_payment_url}", { paymentID: data.paymentID, payerID: data.payerID }).then(function() { submitOrderPaypal(data.paymentID) }); } else { return $.post("#{paypal_execute_subscription_url}", { subscriptionToken: data.orderID }).then(function(executeData) { submitOrderPaypal(executeData.id) }); } } }).render('#submit-paypal');

Tworzenie i wykonywanie subskrypcji ma podobną logikę, jak w przypadku płatności. Jedna różnica polega na tym, że podczas wykonywania płatności dane z funkcji zwrotnej onApprove mają już paymentID reprezentujący charge_id do przesłania formularza poprzez submitOrderPaypal(data.paymentID) . W przypadku subskrypcji uzyskujemy identyfikator charge_id dopiero po jego wykonaniu, żądając POST na paypal_execute_subscription_url , więc możemy wywołać submitOrderPaypal(executeData.id) .

Krok 7: Przetestuj swoją aplikację.

  • Odwiedź stronę indeksu.
  • Wybierz produkt subskrypcyjny i PayPal jako metodę płatności.
  • Kliknij przycisk prześlij PayPal.
  • W wyskakującym okienku PayPal:
    • Użyj danych logowania do utworzonego konta kupującego.
    • Zaloguj się i potwierdź zamówienie.
    • Wyskakujące okienko powinno się zamknąć.
  • Sprawdź, czy zostałeś przekierowany na stronę sukcesu.
  • Na koniec sprawdź, czy zamówienie zostało zrealizowane na koncie PayPal, logując się na swoje konto firmowe na https://www.sandbox.paypal.com/signin i sprawdzając pulpit nawigacyjny https://www.sandbox.paypal.com/listing/ transakcje.

Wniosek

Po przeczytaniu tego artykułu powinieneś być w stanie zintegrować płatności/opłaty, a także transakcje subskrypcji dla PayPal i Stripe w swojej aplikacji Rails. Istnieje wiele punktów, które można poprawić, których nie dodałem w tym artykule ze względu na zwięzłość. Wszystko zorganizowałem w oparciu o założenie trudności:

  • Łatwiej:
    • Użyj protokołu Transport Layer Security (TLS), aby Twoje żądania korzystały z protokołu HTTPS.
    • Implementuj konfiguracje środowiska produkcyjnego zarówno dla PayPal, jak i Stripe.
    • Dodaj nową stronę, aby użytkownicy mieli dostęp do historii poprzednich zamówień.
  • Średni:
    • Zwróć lub anuluj subskrypcje.
    • Zapewnij rozwiązanie dla płatności niezarejestrowanych użytkowników.
  • Trudniej:
    • Zapewnij sposób na usunięcie kont i zachowanie ich tokena i identyfikatora klienta , jeśli użytkownik chce wrócić. Ale po upływie określonej liczby dni usuń te dane, aby Twoja aplikacja była bardziej zgodna z PCI.
    • Przejdź do API PayPal w wersji 2 po stronie serwera (https://developer.paypal.com/docs/api/payments/v2/) Klejnot, którego użyliśmy w tym samouczku paypal-sdk-rest , ma tylko wersję beta dla wersji 2, aby można było z niego korzystać ostrożnie (https://github.com/paypal/PayPal-Ruby-SDK/tree/2.0-beta).
    • Uwzględnij żądania idempotentne.
      • Pasek: https://stripe.com/docs/api/idempotent_requests
      • PayPal: https://developer.paypal.com/docs/api-basics/#api-idempotency

Polecam również przeczytać o elemencie Stripe Checkout, który jest kolejnym sposobem na zintegrowanie Stripe z frontendem. W przeciwieństwie do Stripe Elements, których użyliśmy w tym samouczku, Stripe Checkout otwiera wyskakujące okienko po kliknięciu przycisku (podobnie jak w systemie PayPal), w którym użytkownik podaje informacje o karcie kredytowej LUB wybiera płatność za pomocą Google Pay/Apple Pay https://stripe.com /dokumenty/sieć.

Zaleceniem do drugiego czytania są strony bezpieczeństwa dla obu bramek płatności.

  • Na pasek
  • Dla PayPal

Na koniec dziękuję za przeczytanie tego artykułu! Możesz również sprawdzić mój projekt GitHub używany w tym przykładzie projektu. Tam dodałem również testy rspec podczas programowania.