Płatności w railsach

Wypełniając obietnicę złożoną jakiś czas temu niniejszym udostępniam kod pozwalający na integrację aplikacji Railsowej z serwisem platnosci.pl. Ponieważ integracja to nie tylko sam plugin przygotowałem także tekst objaśniający (mam nadzieję) tajniki spinania aplikacji z serwisem transakcyjnym. Zapraszam...

Wstęp

Kod który przedstawiam w tym artykule pochodzi z prawdziwej i żywej aplikacji – webankieta.pl. Działa sprawnie od kilku miesięcy przetwarzając wszystkie zamówienia składane przez moich klientów. Nie można jednak wykluczyć, że w Twoim przypadku coś zacznie działać błędnie. Z tego też względu ostrzegam: używasz przedstawionego tu kodu na własną odpowiedzialność.
Plugin i przykładowa aplikacja były testowane z Railsami w wersji 1.2.x, pliki z kodami źródłowymi są zapisane jako UTF-8.

Zanim rozpoczniemy integrację z systemem transakcyjnym musimy posiadać:

  • aktywne konto w platnosci.pl – niestety płatności nie udostępniają konta developerskiego, więc wszystkie testy i próby musimy przeprowadzać na swoim własnym koncie. Na szczęście jest możliwość ustawienia testowego sposobu płatności co pozwala na symulowanie transakcji bez ponoszenia kosztów związanych z prowizją.
  • komputer widziany z Internetu - w konfiguracji konta w platnosci.pl będziemy musieli podać urle pod którymi będzie dostępna w sieci nasza aplikacja – wynika to ze sposobu działania całego systemu.

Jak są obsługiwane płatności?

Opis interakcji z systemem platnosci.pl jest szczegółowo wyjaśniony w dokumentacji. Tutaj przedstawiam go więc tylko w skróconej postaci przydatnej w zrozumieniu jak działa kod plugina i gdzie ewentualnie szukać przyczyn błędów podczas samodzielnej integracji.

Oto jak przebiega obsługa płatności:
Klient po podjęciu decyzji o zakupie wchodzi na stronę z formularzem który pozwala mu m.in. wybrać sposób opłacenia zamówienia. Po wyborze rodzaju płatności klika ‘Płacę’ i następuje wysłanie formularza do serwera platnosci.pl. W zależności od rodzaju płatności klient jest przekierowywany na stronę banku, do centrum przetwarzającego karty płatnicze albo widzi wypełniony druk przelewu. Klient podaje oczekiwane informacje i kończy swoje zamówienie. W zależności od efektu następuję przekierowanie do Sklepu z informacją o sukcesie albo błędzie (w dokumentacji odpowiednio UrlPozytywny i UrlNegatywny). Ważne: to przekierowanie nie może służyć jako sygnał do przetwarzania danych w sklepie.

Po pewnym czasie (zwykle kilka sekund) do Sklepu przekazywany jest raport który stanowi informację, że status danej transakcji się zmienił. Raport to request GET wysłany przez serwer platnosci.pl na podany w konfiguracji adres w Sklepie. Sklep jest zobowiązany samodzielnie pobrać szczegóły podanej transakcji i potwierdzić odbiór danych. Jeżeli serwer Sklepu jest niedostępny albo nie zostanie odesłane prawidłowe potwierdzenie będą podejmowane kolejne próby. Po setnej nieudanej próbie raport przestaje być wysyłany, a do właściciela sklepu trafia mail z informacją o błędzie. Historia raportów dla każdej z transakcji jest dostępna w panelu administracyjnym.

Wersja rysunkowa prezentuje się tak:

Diagram

Przykładowa aplikacja

Ponieważ najlepiej uczyć się psując coś co działa przygotowałem testową aplikację na której można przetestować komunikację z systemem transakcyjnym.
Przed uruchomieniem konieczna jest konfiguracja konta w platnosci.pl i ustawienie parametrów konfiguracyjnych w samej aplikacji.

Konfiguracja POSa
Zaczynamy od konfiguracji konta w panelu administracyjnym platnosci.pl.
W istniejącym lub nowym sklepie tworzymy testowy punkt płatności (POS) – to z nim będzie się komunikowała aplikacja. Właśnie tu potrzebny jest publiczny adres do testowego komputera. Wypełniamy kolejno:

  • w polu ‘Nazwa punktu płatności’ wpisując np. ‘testowy POS’
  • w polu ‘Adres powrotu błędnego’ wpisując: http://adreskompa/transaction/error?order_id=%orderId%&error_code=%error%&trans_session_id=%sessionId% - tu będzie przekierowanie gdy system transakcyjny wykryje błąd np. braki w danych,
  • w polu ‘Adres powrotu pozytywnego’ wpisując: http://adreskompa/transaction/success?order_id=%orderId%&trans_session_id=%sessionId% - tu nastąpi przekierowanie gdy transakcja przebiegnie pomyślnie,
  • w polu ‘Adres raportów statusu’ wpisując: http://adreskompa/transaction/report - ten adres będzie wywoływany przez serwer platnosci.pl aby poinformować aplikację o zmianie statusu transakcji,
  • Kodowanie ustawiamy na UTF-8

Jak widać w adresach UrlPozytywny i UrlNegatywny przekazywane są zwrotnie: numer zamówienia (order_id), kod błędu (error_code) i id transakcji (trans_session_id). W podobny sposób można przekazać jeszcze inne parametry – szczegóły w dokumentacji.

Po utworzeniu POSa system platnosci.pl tworzy dodatkowe parametry. Ich wartości będą potrzebne w aplikacji, ze szczegółów POSa kolejno odczytujemy:

  • ‘Id punktu płatności’ dalej przedstawiany jako pos_id,
  • ‘Klucz (MD5)’ dalej przedstawiany jako key1,
  • ‘Drugi klucz (MD5)‘ dalej przedstawiany jako key2.

W tabeli z typami płatności włączamy także ‘Płatność testową’. W ten sposób konfiguracja testowego POSa dobiegła końca.

Konfiguracja aplikacji
Drugim krokiem konfiguracyjnym jest przeniesienie parametrów pos_id, key1, key2 do aplikacji. W pliku conf/environment.rb i w okolicach linii 49 wpisujemy wartości dla naszego POSa:

RUBY:
  1. TransactionSupport.config.key1 =   #tu wartość key1
  2. TransactionSupport.config.key2 =   #tu wartość key2
  3. TransactionSupport.config.pos_id = #tu wartość pos_id

Na zakupy :)
Aplikacja jest gotowa do testów, uruchamiamy więc serwer

ruby script/server

i jeżeli wszystko poszło dobrze pod adresem http://adreskompa/transaction/ powinna się pokazać strona z formularzem do złożenia zamówienia podobnym do tego:

Formularz

Formularz zawiera tylko absolutnie wymagane pola, usunięcie zawartości np. ‘Identyfikator płatności:’ spowoduje więc przekierowanie na stronę UrlNegatywny. Jeżeli formularz zostanie wysłany w bez zmian powinna się wyświetlić strona pozwalająca na anulowanie lub zatwierdzenie testowej płatności. W ten sposób można stworzyć płatności które będą już widoczne w panelu administracyjnym platnosci.pl jako transakcje testowe.
Link ‘Wersja z wyborem typu płatności via JS’ prowadzi do tej samej strony ale z wyświetloną pełną listą typów płatności. Teraz można już wybrać np. ‘prawdziwy’ przelew i przekazać pieniądze na własne konto w platnosci.pl (oczywiście od tej transakcji zostanie pobrana prowizja :)) . Lista jest tworzona dynamicznie za pomocą JS pobranego z serwisu transakcyjnego.

Moja przykładowa aplikacja daje tylko ogólny pogląd tego jak integruje się aplikację z system platnosci.pl. Przy prawdziwej aplikacji trzeba uwzględnić jeszcze wiele innych aspektów jak choćby: obieg zamówień w aplikacji, aktualizację stanów w zależności od statusu zamówienia, rozsyłanie informacji do klientów itd.
Integracja zawsze jednak będzie zawierała następujące kroki:

  1. Instalacja plugina

    Plugin jest dostępny wprost z repozytorium SVN, ze względu na jego lokalną specyfikę nie rejestrowałem go w globalnym repo. Instalacja wymaga więc wskazania repozytorium:

    CODE:
    1. ruby script/plugin install http://svn.jarmark.org/rails/transaction_support/

  2. Konfiguracja

    Konfiguracja rozumiana zarówno jako ustawienie parametrów POSa w panelu administracyjnym platnosci.pl, jak i wstawienie wartości parametrów pos_id, key1, key2 w conf/environment.rb.

  3. Formularz zamówienia

    W helperze widocznym w szablonie w którym jest budowany formularz zamówienia umieszczamy kod:

    RUBY:
    1. include TransactionSupport::PlatnosciPl::ViewHelper

    Powoduje on udostępnienie w szablonie dwóch metod pomocniczych: new_payment_url i include_javascript_paytype.
    Metoda new_payment_url zwraca adres pod który musi być wysłany gotowy formularz zamówienia, wstawiamy ją więc jako atrybut ‘action’ formularza.
    Druga metoda include_javascript_paytype pozwala na włączenie kodu JavaScript z dynamiczną listą typów płatności. Plik jest pobierany wprost z serwera platnosci.pl.

  4. Akcja dla raportów

    Kluczowym elementem związanym z przetwarzaniem płatności po stronie integrowanej aplikacji jest akcja wywoływana przez serwis transakcyjny. Akcja ta jest odpowiedzialna za pobranie informacji o transakcji z serwera platnosci.pl i dalsze przetworzenie tej informacji z uwzględniem specyfiki aplikacji.
    Z grubsza akcja może wyglądać tak:

    RUBY:
    1. def report
    2.         result = 'OK'
    3.         begin
    4.             state = TransactionSupport.get_state(params)
    5.             unless state.error?
    6.                 # nie ma blędu mozemy rozpocząc przetwarzanie informacji o transakcji
    7.                 # w szczegolnosci dostępne są informacje o stanie transakcji:
    8.                 case
    9.                     when state.new?:       logger.info("Nowo rozpoczeta transakcja")
    10.                     when state.received?:  logger.info("Pieniadze na koncie...")
    11.                     when state.cancelled?: logger.info("Transakcja zostala anulowana.")
    12.                 end
    13.             else
    14.                 logger.error("Coś się nie udało...")
    15.                 raise StandardError, "Response failure."
    16.             end
    17.         rescue => e
    18.             logger.error("Wystapil blad. Details:\n#{$!}\n#{$@}")
    19.             result = "ERROR: #{e.class}:#{e.message}"
    20.         end
    21.         render(:text=>result)
    22.     end

  5. Testy

    Metoda testująca integracje z systemem transakcyjnym może wyglądać tak:

    RUBY:
    1. # wszystko powinno zakonczyc sie pomyslnie sprawdzam transakcje ktora istnieje i ma sie dobrze:)
    2.     def test_get_state_ok
    3.         TransactionSupport.config.key1=KEY1
    4.         TransactionSupport.config.key2=KEY2
    5.         TransactionSupport.config.pos_id=POS_ID
    6.         TransactionSupport.config.http_debug_stream = $stderr
    7.  
    8.         payment = TransactionSupport.get_state('tutaj wartosc trans_session_id zamowienia ktore rzeczywiscie istnieje w sytemie')
    9.  
    10.         #puts payment.inspect
    11.         assert_equal false, payment.error?
    12.         assert payment.received?
    13.         assert_nil payment.error_code
    14.         assert_nil payment.error
    15.         assert_nil payment.error_details
    16.     end

Zakończenie

Jak zaznaczyłem na wstępie przedstawiony tu kod doskonale spisuje się w warunkach produkcyjnych nie jest to jednak implementacja pełnego API jakie udostępniają platnosci.pl. Jednym z możliwych kierunków rozwoju byłoby więc rozszerzenie o brakujące funkcje, innym (chyba ciekawszym) byłoby dodanie obsługi innych systemów transakcyjnych. Konstrukcja plugina pozwala na stosunkowo proste rozszerzenie o connectory do innych systemów – jeżeli znalazłby się ktoś chętny mogę pomóc.

[ ]
Spodobało się? Podziel się z innymi: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • del.icio.us
  • Wykop
  • Gwar
  • Digg
  • Technorati

Liczba komentarzy: 2 »

  1. Darek Rusin said,

    kwiecień 20, 2007 @ 13:22

    Ha! Super, dzieki, ze Ci się chciało i znalazłeś czas. W końcu (kiedyś) będę chciał zrobić obsługę kart kredytowych na www.ezosfera.pl i wtedy skorzystam z Twojej pracy.

  2. Przykładowy stos technologiczny dla startupu : Ruby on Rails said,

    sierpień 6, 2007 @ 20:25

    […] transaction_support […]

RSS feed for comments on this post · Adres TrackBack

Dodaj komentarz