ActiveMerchant में ऑनलाइन पैसा एकीकृत करें

मैं रूबी ऑन रेल पर जो एप्लिकेशन विकसित कर रहा हूं, उसमें मुझे भुगतान प्रणाली को जोड़ने की जरूरत है। ग्राहक ने मनी ऑनलाइन के साथ एक समझौता किया, और पहली चीज़ जो मैंने की, निश्चित रूप से, Shopify ActiveMerchant में समर्थित सिस्टम की सूची की जाँच कर रहा था - यह सेवा वहाँ नहीं थी, मैंने ऐसे तैयार समाधानों की भी तलाश की, जो एकीकरण को सरल बना सके, लेकिन RoR के तहत उपयोगी कुछ भी नहीं था। परिणामस्वरूप, ActiveMerchant को कांटा और इसके लिए इस सेवा के लिए एकीकरण विकसित करने का निर्णय लिया गया, और बाद में परियोजना में अनुभव का उपयोग करें।

इस लेख में मैं एक भुगतान प्रणाली को जोड़ने की प्रक्रिया के बारे में बात करना चाहता हूं, इस उम्मीद में कि यह किसी के लिए उपयोगी होगा, क्योंकि मुझे ऐसी जानकारी की कमी है। यह भी संभव है कि जानकारी किसी के लिए उपयोगी होगी, विशेष रूप से इस भुगतान प्रणाली पर।

इससे पहले, मेरे पास पहले से ही ActiveMerchant का एक परिचित था: जिन परियोजनाओं में मैंने Robokassa को एकीकृत किया था, उनमें से एक में - तब इस लेख ने बहुत मदद की, और मुझे कोई समस्या नहीं हुई, लेकिन मुझे मॉड्यूल कार्यान्वयन कोड को केवल कुछ बार जांचने या समझने के लिए देखना पड़ा किसी भी विशिष्ट तरीकों का काम - वह सब है और अपने मॉड्यूल को एकीकृत करते समय, मुझे ActiveMerchant का एक बड़ा हिस्सा सीखना पड़ा।

ActiveMerchant संरचना

ऐसी सेवाओं को एकीकृत करने में मदद के लिए, परियोजना में 3 आधार वर्ग हैं:


भुगतान प्रणाली के प्रत्येक कार्यान्वयन में आधार से विरासत में मिली कई कक्षाएं शामिल हैं, कुछ मॉड्यूल में अतिरिक्त कक्षाएं हैं जो प्रोटोकॉल की अतिरिक्त विशेषताओं को लागू करती हैं। ActiveMerchant में प्रत्येक भुगतान प्रणाली के लिए भी एक मॉड्यूल है जिसमें कक्षाएं फ़ाइलों से भरी हुई हैं, और जिसमें एक विशिष्ट वर्ग बनाने के लिए विधियाँ हैं जो इस मॉड्यूल में शामिल हैं।

ActiveMerchant में ऑनलाइन पैसा एकीकृत करें

इस समस्या का समाधान मनी ऑनलाइन प्रोटोकॉल के अध्ययन के साथ शुरू हुआ, और सब कुछ इतना पारदर्शी नहीं हुआ जितना कि रोबोकैसा के मामले में: सूचना, पुष्टि और कॉलबैक की पृष्ठभूमि का सत्यापन, वास्तव में, सब कुछ सरल है, लेकिन अधिक हद तक मैं अनुरोधों के दौरान प्रेषित मापदंडों से भ्रमित था और बहुत से अलग-अलग। आरक्षण।

छवि
सामान्य क्वेरी योजना

संक्षेप में: सामान्य स्थिति में, एक सकारात्मक परिदृश्य में, सब कुछ इस तरह होता है: साइट सिस्टम को सभी आवश्यक मापदंडों के साथ एक फॉर्म भेजती है, जबकि उपयोगकर्ता भुगतान प्रणाली वेबसाइट पर जाता है, फिर पृष्ठभूमि में भुगतान प्रणाली हमारी वेबसाइट से डेटा की शुद्धता की पुष्टि करने के लिए कहती है। यदि डेटा सही है, तो उपयोगकर्ता को पुनर्निर्देशित किया जाएगा जहां वह भुगतान करने के लिए आवश्यक निर्देश देखता है। "भुगतान" बटन पर क्लिक करने के बाद, भुगतान प्रणाली भुगतान स्वीकार करने से पहले डेटा की शुद्धता की फिर से जांच करेगी, फिर भुगतान स्वीकार किया जाएगा और सिस्टम साइट पर भुगतान की पुष्टि के लिए अनुरोध भेजेगा, और यदि जवाब हाँ है, तो उपयोगकर्ता कॉलबैक पर पुनर्निर्देशित किया जाएगा।

प्रोटोकॉल की मुख्य विशेषताएं जो मुझे भ्रमित करती हैं:


इन विशेषताओं के कारण, मुझे उनके समर्थन में कई बार लिखना पड़ा (हालांकि पहले तो मैंने साइट पर वॉयस मॉड्यूल के माध्यम से उनसे संपर्क किया, लेकिन लड़की ने मेरी समस्या को सुनने के बाद मुझे एक उत्तर देने वाली मशीन पर पुनर्निर्देशित कर दिया), और उसी दिन के भीतर पर्याप्त उत्तर दिए।

प्लसस में से, मैंने देखा कि यदि आप वर्णित प्रोटोकॉल के अनुसार एक अनुरोध करते हैं, तो आपको प्रतिक्रिया में अपेक्षित परिणाम मिलेगा, हालांकि कुछ मामलों में डेटा की जांच नहीं की जाती है, लेकिन जाहिरा तौर पर गेटवे की सुविधाओं के कारण।

मुझे कुछ मामलों में पृष्ठभूमि में बिल करने की क्षमता भी पसंद आई। और मैंने बिलिंग प्रोटोकॉल का समर्थन यथासंभव पूरा करने का निर्णय लिया, लेकिन मेरे पास बिल्कुल सब कुछ परीक्षण करने का अवसर नहीं था, इसलिए शायद कुछ समस्याएं हो सकती हैं।

हम एक अनिर्दिष्ट अवसर की पहचान करने में भी कामयाब रहे: QIWI के माध्यम से भुगतान के लिए एक खाता बनाने की पृष्ठभूमि के अनुरोध के जवाब में, वर्णित मापदंडों के साथ आता है, अतुल्य सामग्री के साथ iframeSRC पैरामीटर, दो बार सोचने के बिना, इस पैरामीटर से डेटा को base64 के साथ डिकोड किया और एक लिंक प्राप्त किया जो फ़ॉर्म की ओर जाता है। QIWI के माध्यम से भुगतान, और यह स्पष्ट रूप से माना जाता है कि लिंक का उपयोग एक आइफ्रेम बनाने के लिए किया जाना चाहिए।

यदि आप ActiveMerchant में भुगतान प्रणाली एकीकरण के विभिन्न कार्यान्वयनों को देखते हैं, तो आप देख सकते हैं कि एक ही कोड कई मॉड्यूल में कैसे प्रवाहित हो सकता है, कुछ फ़ाइलों में कोड कई मॉड्यूल से कोड का संयोजन हो सकता है, और इसी तरह, लेकिन कोई भी जटिल नहीं है परिदृश्यों। मुझे अपना स्वयं का बहुत कुछ लिखना था, विशेष रूप से पृष्ठभूमि प्रश्नों के कार्यान्वयन के लिए, इसलिए मुझे डर है कि अनुरोध पूल को मंजूरी नहीं दी जाएगी, हालांकि संक्षेप में मैंने उन सभी संभावनाओं और विचारों को बचाया जो आधार कक्षाएं उनके कार्यान्वयन में लेती हैं, बस कुछ नए जोड़े गए।

अंत में जो हुआ वह यहाँ देखा जा सकता है । सहायक के लिए सामान्य अवधारणा के ढांचे से परे जाने वाली एकमात्र चीज डेटा सत्यापन है, लेकिन सामान्य तौर पर इसकी बिल्कुल आवश्यकता नहीं है, इसका उपयोग केवल अनुरोध के पहले ही संभावित त्रुटियों से बचने के लिए पृष्ठभूमि अनुरोधों के साथ किया जाना चाहिए (मेरे मामले में इसके बावजूद) साइट पर भुगतान प्रणाली को लागू करते समय, मुझे इसके बारे में गंदे तरीके से प्राप्त करना पड़ता था), और कुछ अनुरोध पैरामीटर स्वचालित रूप से विशेष मामलों में सेट होते हैं, ताकि डेवलपर को लंबे समय तक प्रोटोकॉल से निपटना न पड़े। मेरे सहायक के पास एक बैकग्राउंड रिक्वेस्ट भेजने का अवसर भी है, अगर यह वैध मोड_टाइप के लिए किया जाता है, तो उत्तर स्वचालित रूप से पार्स हो जाता है और इस उत्तर के साथ काम करना सुविधाजनक होगा।

मैं यह नहीं कह सकता कि कोड अच्छा निकला, क्योंकि मैं लगभग तीन महीने से माणिक से परिचित हूं, इसलिए मुझे किसी भी मदद या सलाह पर खुशी होगी, मैं उन लोगों की मदद करने के लिए भी तैयार हूं जो किसी भी भुगतान प्रणाली को ActiveMant में एकीकृत करना चाहते हैं।

किसी साइट पर भुगतान प्रणाली बनाने का एक उदाहरण

सबसे पहले, आपको प्रोजेक्ट में ActiveMerchant शामिल करने की आवश्यकता है, इसके लिए हम इसे Gemfile में जोड़ते हैं
gem 'activemerchant', :git => "https://github.com/ovcharik/active_merchant.git", :branch => "dengionline" 

अब तक, आप इसे जोड़ सकते हैं, लेकिन मैंने आधिकारिक पूल को अनुरोध पूल भेजा था, और शायद इसे जल्द ही मंजूरी मिल जाएगी।

अगला, आवश्यक राउटर बनाएं
 scope 'top_up' do post 'create' => 'top_up#create', :as => 'top_up_create' post 'notify' => 'top_up#notify', :as => 'top_up_notify' post 'check' => 'top_up#check', :as => 'top_up_check' match 'success' => 'top_up#success', :as => 'top_up_success' match 'fail' => 'top_up#fail', :as => 'top_up_fail' end 


अंतिम 4 पते पंजीकरण में भुगतान प्रणाली को इंगित करते हैं: इस प्रक्रिया में, एक प्रश्नावली भरना आवश्यक होगा जिसमें इन पते पर अंक हों। साइट स्वयं पते बदलने की क्षमता प्रदान नहीं करती है, और यह केवल अतिरिक्त समर्थन अनुरोधों के माध्यम से किया जाता है, इसलिए मुझे सीधे उत्पादन में बहुत परीक्षण करना पड़ा (इस तथ्य के बावजूद कि परियोजना शुरू की गई थी, यह अभी भी विकास के तहत है और इससे उपयोगकर्ताओं को प्रभावित नहीं किया गया)।

मेरे द्वारा किए जा रहे प्रोजेक्ट में, सेवाओं के लिए भुगतान करते समय यह परिदृश्य होता है: उपयोगकर्ता, "भुगतान" बटन पर क्लिक करके / ajax अनुरोध को / top_up / create पर भेजता है, वहां डेटा की जाँच की जाती है, फिर भुगतान प्रणाली के लिए एक पृष्ठभूमि अनुरोध भेजा जाता है, उपयोगकर्ता को एक सफल प्रतिक्रिया प्रदर्शित होती है, त्रुटियों को अलग से संसाधित किया जाता है। । मेरे मामले में, एक सफल प्रतिक्रिया के रूप में, छिपे हुए फ़ील्ड के साथ एक फॉर्म आता है और इसके तुरंत बाद एक स्क्रिप्ट आती है जो इस फॉर्म को भेजती है, अर्थात, यदि यह प्रतिक्रिया पृष्ठ पर कहीं दिखाई जाती है, तो उपयोगकर्ता को मुख्य रूप से गेटवे पृष्ठ पर पुनर्निर्देशित किया जाएगा जो वह पूरा कर सकता है भुगतान।

पृष्ठभूमि अनुरोध के दौरान, निम्न होता है: मैं एक पृष्ठभूमि अनुरोध करता हूं, सिस्टम सभी डेटा की जांच करता है और यदि यह सही है, तो यह / top_up / चेक विधि को कॉल करता है, जहां इसे एक सकारात्मक जवाब मिलना चाहिए, सिस्टम की जांच के बाद आवश्यक डेटा लौटाता है।

गेटवे वेबसाइट पर, उपयोगकर्ता एक फॉर्म देखता है जहां उसे विवरण निर्दिष्ट करने की आवश्यकता होती है, और "भुगतान" बटन पर क्लिक करने के बाद, गेटवे मनी ऑनलाइन सिस्टम में डेटा की जांच करता है, जो बदले में परियोजना में डेटा (फिर से / top_up / चेक) पर एक प्रतिक्रिया प्राप्त करता है और इसे पेमेंट गेटवे तक पहुंचाता है। वह भुगतान की पुष्टि करता है और इसके बारे में भुगतान प्रणाली को सूचित करता है, और वह पहले से ही साइट (/ top_up / सूचना) को एक अधिसूचना भेजता है, और उसी समय उपयोगकर्ता को कॉलबैक में वापस कर दिया जाता है।

बस लॉग देखकर इस प्रक्रिया को समझना आसान हो सकता है।
 Started POST "/ru/top_up/create" for user_ip at 2013-10-05 14:45:00 +0400 Processing by TopUpController#create as */* Parameters: {"amount"=>"1.0", "authenticity_token"=>"token", "currency"=>"RUB", "order"=>"78", "lang"=>"ru"} Started POST "/top_up/check" for deingionline_ip at 2013-10-05 13:45:00 +0400 Processing by TopUpController#check as */* Parameters: {"amount"=>"0", "userid"=>"example@mail.com", "userid_extra"=>"58", "paymentid"=>"0", "key"=>"key1"} Rendered text template (0.0ms) Completed 200 OK in 16ms (Views: 1.1ms | ActiveRecord: 2.5ms) Completed 200 OK in 557ms (Views: 0.5ms | ActiveRecord: 11.1ms) Started POST "/top_up/check" for deingionline_ip at 2013-10-05 14:46:20 +0400 Processing by TopUpController#check as */* Parameters: {"amount"=>"0", "userid"=>"example@mail.com", "userid_extra"=>"58", "paymentid"=>"0", "key"=>"key1"} Rendered text template (0.0ms) Completed 200 OK in 19ms (Views: 1.0ms | ActiveRecord: 1.9ms) Started POST "/top_up/notify" for deingionline_ip at 2013-10-05 14:46:20 +0400 Processing by TopUpController#notify as */* Parameters: {"amount"=>"1.00", "userid"=>"example@mail.com", "userid_extra"=>"58", "paymentid"=>"123456789", "paymode"=>"mode_type", "orderid"=>"58", "key"=>"key2"} Rendered text template (0.0ms) Completed 200 OK in 127ms (Views: 0.9ms | ActiveRecord: 15.2ms) Started GET "/top_up/success" for user_ip at 2013-10-05 14:46:30 +0400 Processing by TopUpController#success as HTML Rendered ... Completed 200 OK in 21ms (Views: 16.6ms | ActiveRecord: 0.7ms) 


लॉग में आप देख सकते हैं कि सभी मामलों में कौन से पैरामीटर ट्रांसमिट किए गए हैं, और जब / टॉप_अप / चेक एक्सेस करते हैं, तो भुगतान प्रणाली ऑर्डरिड (प्रोजेक्ट में आंतरिक भुगतान पहचानकर्ता, भुगतान प्रणाली में भुगतानकर्ता पहचानकर्ता) को प्रेषित नहीं करती है, इसलिए भुगतान की पहचान करने के लिए userid_extra पैरामीटर का उपयोग करने का निर्णय लिया गया था, लेकिन यहां आपको सावधान रहने की भी आवश्यकता है, क्योंकि कुछ मामलों में यह वापस नहीं आता है, आप उपयोगकर्ता के आंतरिक भुगतान नंबर को निर्दिष्ट कर सकते हैं, लेकिन भुगतान प्रणाली में आपके खाते में, आप सभी लेनदेन देख सकते हैं, साथ ही साथ चुन सकते हैं यह पैरामीटर, और यदि आप इस पैरामीटर के रूप में एक विशिष्ट पहचानकर्ता का उपयोग करते हैं, तो नमूना विकल्प की उपयोगिता शून्य होगी।

नियंत्रक
 class TopUpController < ApplicationController include ActiveMerchant::Billing::Integrations #    create skip_before_filter :verify_authenticity_token, :except => [:create] #     ActiveMerchant before_filter :create_notification, :only => [:check, :notify] #    before_filter :find_payment, :only => [:check, :notify] #   def create authorize! :create, Payment r = { :success => false, :errors => {:base => []} } errors = false #    ,      #   activemerchant     @payment = Payment.new({ :user => current_user, :amount => params[:amount] }) #   unless errors or @payment.save r[:errors].merge! @payment.errors.messages errors = true end unless errors #    ActiveMerchant helper=Dengionline.helper @payment.id, CONFIG["dengionline"]["project"], { :amount => @payment.amount, :nickname => @payment.user.email, #     :nick_extra => @payment.id, #         :transaction_type => CONFIG["dengionline"]["mode_type"], #           :source => CONFIG["dengionline"]["source"], #  ,       :secret => CONFIG["dengionline"]["secret"], #    ,      , :method => :credit_card, :mode => :background } begin #    ,    mode_type   #  ,    ,   - #      ,    xml, #     # ,       mode_type #       if (helper.valid? or helper.errors.size > 1 or helper.errors[0] != "mode_type") r[:errors][:base] << I18n.t("views.top_up.create.technical_error") break end #   ,     #       response = helper.background_request! #      ,   xml #    if response.errors.empty? and response.fail? r[:errors][:base] << response.comment break end #    parse_error -  ,     #      200 if (response.success? or response.errors.empty? or response.errors.size > 1 or response.errors[0] != "parse_error") r[:errors][:base] << I18n.t("views.top_up.create.gateway_error") break end #   parse_error,      #      ,     #    ,    r[:success] = true r[:body] = response.body end until true end render :json => r end #   def check if (@notification.acknowledged? and @payment and @payment.wait? and @payment.valid?) render :text => @notification.generate_response("YES") else render :text => @notification.generate_response("NO") end end #   def notify if (@notification.acknowledged? and @payment and @payment.amount == @notification.amount and @payment.amount > 0) #       #      #              #      saved = true if @payment.wait? @payment.do_payment_id = @notification.payment_id @payment.paid! saved = @payment.save Notifier.payment_paid(@payment).deliver if saved end if @payment.paid? and saved render :text => @notification.generate_response("YES") else render :text => @notification.generate_response("NO") end else render :text => @notification.generate_response("NO") end end #      def success end def fail end private def create_notification @notification = Dengionline.notification(request.raw_post, { :secret => CONFIG["dengionline"]["secret"] }) end def find_payment #  ,     nil,   @payment = Payment.where(:id => @notification.nick_extra).first end end 


मेरे पास प्रतिक्रियाओं की प्रकृति के कारण पृष्ठभूमि में भेजे गए सभी डेटा हैं, लेकिन आप यहां वर्णित विधि का उपयोग भी कर सकते हैं

मैं दूरस्थ भुगतान जानकारी प्राप्त करने के लिए कक्षा का उपयोग करने का एक उदाहरण भी दूंगा, मुझे लगता है कि किसी को भी इसका उपयोग करने में कोई समस्या नहीं होगी।

उदाहरण
 $ rails c irb(main):001:0> Dengionline = ActiveMerchant::Billing::Integrations::Dengionline => ActiveMerchant::Billing::Integrations::Dengionline irb(main):002:0> status = Dengionline.status 69, 1234, :secret => "secret" => #<ActiveMerchant::Billing::Integrations::Dengionline::Status:0xb805bb4> irb(main):003:0> status.to_hash => { "id"=>123456789, "amount_rub"=>"1.00", "status"=>9, "status_description"=>"Success", "order"=>"69", "nick"=>"example@mail.com", "date_payment"=>"2013-10-05T13:00:00+04:00", "paymode"=>"mode_type", "currency_project"=>"RUB", "amount_project"=>"1.00", "currency_paymode"=>"RUB" } 


इस उदाहरण में, आंतरिक भुगतान पहचानकर्ता को मुख्य पैरामीटर के रूप में पारित किया जाता है, यदि आपने बिलिंग करते समय इसका उपयोग नहीं किया है, तो आप भुगतान प्रणाली के भुगतान पहचानकर्ता को स्थानांतरित कर सकते हैं, इसके लिए अंतिम पैरामीटर: भुगतान => payment_id के साथ निर्दिष्ट करें।

Source: https://habr.com/ru/post/In196978/


All Articles