# π³ Sberbank::Acquiring [](https://travis-ci.org/panasyuk/sberbank-acquiring) π»Ruby Version 2.1 - 2.6 (+ JRuby) πΠΠΈΠΊΠ°ΠΊΠΈΡ ΡΡΠΎΡΠΎΠ½Π½ΠΈΡ Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠ΅ΠΉ ## ΠΠΏΠΈΡΠ°Π½ΠΈΠ΅ GEM sberbank-acquiring ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»ΡΠ΅Ρ ΡΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π»ΡΠ½ΠΎΡΡΡ Π΄Π»Ρ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΡ Ρ API ΡΠΊΠ²Π°ΠΉΡΠΈΠ½Π³Π° Π±Π°Π½ΠΊΠ° Π‘Π±Π΅ΡΠ±Π°Π½ΠΊ. ΠΠ½ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅Ρ RESTful API ΡΠΊΠ²Π°ΠΉΡΠΈΠ½Π³Π° Π‘Π±Π΅ΡΠ±Π°Π½ΠΊΠ°. ΠΠ΅ΡΠ΅Π΄ ΡΠ΅ΠΌ, ΠΊΠ°ΠΊ ΠΏΡΠΈΡΡΡΠΏΠΈΡΡ ΠΊ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ ΡΡΠΎΠ³ΠΎ Π³Π΅ΠΌΠ°, Π°Π²ΡΠΎΡ Π½Π°ΡΡΠΎΡΡΠ΅Π»ΡΠ½ΠΎ ΡΠ΅ΠΊΠΎΠΌΠ΅Π½Π΄ΡΠ΅Ρ (Ρ ΠΎΡΡ Π±Ρ Π±Π΅Π³Π»ΠΎ) ΠΎΠ·Π½Π°ΠΊΠΎΠΌΠΈΡΡΡΡ Ρ ΠΎΡΠΈΡΠΈΠ°Π»ΡΠ½ΠΎΠΉ [Π΄ΠΎΠΊΡΠΌΠ΅Π½ΡΠ°ΡΠΈΠ΅ΠΉ ΠΊ JSON API ΡΠΊΠ²Π°ΠΉΡΠΈΠ½Π³Π° Π‘Π±Π΅ΡΠ±Π°Π½ΠΊΠ°](https://securepayments.sberbank.ru/wiki/doku.php/integration:api:start#%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D1%84%D0%B5%D0%B9%D1%81_rest), Π° ΡΠ°ΠΊ ΠΆΠ΅ [Wiki](https://github.com/panasyuk/sberbank-acquiring/wiki), ΠΊΠΎΠΌΡ ΠΈΠ½ΡΠ΅ΡΠ΅ΡΠ½ΠΎ ## Π£ΡΡΠ°Π½ΠΎΠ²ΠΊΠ° ```ruby # Gemfile gem 'sberbank-acquiring', github: 'panasyuk/sberbank-acquiring' # ΠΈΠ»ΠΈ gem 'sberbank-acquiring', '~> 0.1.0' ``` ## ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ ### SBRF::Acquiring::Client ```ruby # client ΠΎΡΠΏΡΠ°Π²Π»ΡΠ΅Ρ Π·Π°ΠΏΡΠΎΡΡ Π½Π° Π±ΠΎΠ΅Π²ΠΎΠΉ ΡΠ΅ΡΠ²Π΅Ρ ΡΠΊΠ²Π°ΠΉΡΠΈΠ½Π³Π° client = SBRF::Acquiring::Client.new(username: 'username', password: 'password') # test_client ΠΎΡΠΏΡΠ°Π²Π»ΡΠ΅Ρ Π·Π°ΠΏΡΠΎΡΡ Π½Π° ΡΠ΅ΡΡΠΎΠ²ΡΠΉ ΡΠ΅ΡΠ²Π΅Ρ ΡΠΊΠ²Π°ΠΉΡΠΈΠ½Π³Π° test_client = SBRF::Acquiring::Client.new(token: 'token', test: true) ``` ΠΠ»ΠΈΠ΅Π½Ρ ΠΌΠΎΠΆΠ΅Ρ Π²ΡΠΏΠΎΠ»Π½ΡΡΡ ΡΠ»Π΅Π΄ΡΡΡΠΈΠ΅ Π²ΡΠ·ΠΎΠ²Ρ ΠΊ API: | ΠΠ°Π·Π²Π°Π½ΠΈΠ΅ ΠΌΠ΅ΡΠΎΠ΄Π° | ΠΡΡΡ API | | -------------------------------- | --------------------------------------- | | deposit | /payment/rest/deposit.do | | get_order_status_extended | /payment/rest/getOrderStatusExtended.do | | payment | /payment/rest/payment.do | | payment_sber_pay | /payment/rest/paymentSberPay.do | | refund | /payment/rest/refund.do | | register | /payment/rest/register.do | | register_pre_auth | /payment/rest/registerPreAuth.do | | reverse | /payment/rest/reverse.do | | verify_enrollment | /payment/rest/verifyEnrollment.do | ΠΡΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ ΠΎΠΆΠΈΠ΄Π°ΡΡ Π² ΠΊΠ°ΡΠ΅ΡΡΠ²Π΅ Π°Π³ΡΡΠΌΠ΅Π½ΡΠ° `Hash`, Ρ ΠΊΠ»ΡΡΠ°ΠΌΠΈ Π² **underscore**. ΠΡΠΈ ΠΏΠΎΠ΄Π³ΠΎΡΠΎΠ²ΠΊΠ΅ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠΎΠ² ΠΊ ΠΎΡΠΏΡΠ°Π²ΠΊΠ΅, ΡΡΠ° ΡΡΡΡΠΊΡΡΡΠ° ΠΏΡΠ΅ΡΠ΅ΡΠΏΠΈΡ ΡΠ»Π΅Π΄ΡΡΡΠΈΠ΅ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΡ: 1. ΠΡΠ΅ ΠΊΠ»ΡΡΠΈ ΡΠ΅ΠΊΡΡΡΠΈΠ²Π½ΠΎ Π±ΡΠ΄ΡΡ ΡΠΊΠΎΠ½Π²Π΅ΡΡΠΈΡΠΎΠ²Π°Π½Ρ Π² **camelCase** 2. ΠΡΠ΅ Π·Π½Π°ΡΠ΅Π½ΠΈΡ ΠΊΠ»Π°ΡΡΠ° `Hash` Π±ΡΠ΄ΡΡ ΠΏΠ΅ΡΠ΅Π΄Π°Π½Ρ Π² Π²ΠΈΠ΄Π΅ JSON ΠΠ°ΠΏΡΠΈΠΌΠ΅Ρ ΡΡΠΎΡ ΠΊΠΎΠ΄: ```ruby client.register( amount: 1000, order_number: 'order#1', return_url: 'https://example.com/sberbank/success', json_params: { user_email: 'test@example.com' } ) ``` ΡΠ½Π°ΡΠ°Π»Π° ΠΏΡΠΈΠ²Π΅Π΄Π΅Ρ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΡ ΠΊ ΡΠ»Π΅Π΄ΡΡΡΠ΅ΠΌΡ Π²ΠΈΠ΄Ρ: ```ruby { 'amount' => 1000, 'orderNumber' => 'order#1', 'returnUrl' => 'https://example.com/sberbank/success', 'jsonParams' => '{"userEmail":"test@example.com"}' } ``` a Π·Π°ΡΠ΅ΠΌ ΠΏΡΠ΅Π²ΡΠ°ΡΠΈΡ ΠΈΡ Π² ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΡ Π·Π°ΠΏΡΠΎΡΠ°: `amount=1000&orderNumber=order%231&returnUrl=https%3A%2F%2Fexample.com%2Fsberbank%2Fsuccess&jsonParams=%7B%22userEmail%22%3A%22test%40example.com%22%7D` #### Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ Π·Π°ΠΊΠ°Π·Π° Π½Π° 10 ΡΡΠ±Π»Π΅ΠΉ ```ruby response = client.register( amount: 1000, # Π² ΡΠ°ΠΌΡΡ ΠΌΠ΅Π»ΠΊΠΈΡ Π΄ΠΎΠ»ΡΡ Π²Π°Π»ΡΡΡ order_number: 'order#1', return_url: 'https://example.com/sberbank/success' ) ``` ```ruby response.success? # => true response.error? # => false response.data # => { "orderId" => "f3ced54d-45df-7c1a-f3ce-d54d04b11830", "formUrl" => "https://3dsec.sberbank.ru/payment/merchants/sbersafe/payment_ru.html?mdOrder=f3ced54d-45df-7c1a-f3ce-d54d04b11830" } response.order_id # => "f3ced54d-45df-7c1a-f3ce-d54d04b11830" response.form_url # => "https://3dsec.sberbank.ru/payment/merchants/sbersafe/payment_ru.html?mdOrder=f3ced54d-45df-7c1a-f3ce-d54d04b11830" ``` #### ΠΡΠΎΠ²Π΅ΡΠΊΠ° ΡΠΎΡΡΠΎΡΠ½ΠΈΡ Π·Π°ΠΊΠ°Π·Π° ```ruby response = client.get_order_status_extended(order_id: 'f3ced54d-45df-7c1a-f3ce-d54d04b11830') ``` ΠΈΠ»ΠΈ ```ruby response = client.get_order_status_extended(order_number: 'order#1') ``` ```ruby response.data # => # { # "errorCode" => "0", # "errorMessage" => "Π£ΡΠΏΠ΅ΡΠ½ΠΎ", # "orderNumber" => "order#2", # "orderStatus" => 0, # "actionCode" => -100, # "actionCodeDescription" => "", # "amount" => 1000, # "currency" => "643", # "date" => 1531643056391, # "merchantOrderParams" => [], # "attributes" => [{ "name" => "mdOrder", "value" => "aefeb658-48fb-7f37-aefe-b65804b11830" }], # "terminalId" => "123456", # "paymentAmountInfo" => { "paymentState" => "CREATED", "approvedAmount" => 0, "depositedAmount" => 0, "refundedAmount" => 0}, # "bankInfo" => { "bankCountryCode" => "UNKNOWN", "bankCountryName" => "<ΠΠ΅ΠΈΠ·Π²Π΅ΡΡΠ½ΠΎ>" } # } response.attributes # => [{ "name" => "mdOrder", "value" => "aefeb658-48fb-7f37-aefe-b65804b11830" }] response.bank_info # => { "bankCountryCode" => "UNKNOWN", "bankCountryName" => "<ΠΠ΅ΠΈΠ·Π²Π΅ΡΡΠ½ΠΎ>" } ``` ΠΠ°ΠΏΡΠΎΡ ΡΠΎΡΡΠΎΡΠ½ΠΈΡ Π·Π°ΠΊΠ°Π·Π° Ρ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠΎΠΌ Π½Π° Π°Π½Π³Π»ΠΈΠΉΡΠΊΠΎΠΌ ΡΠ·ΡΠΊΠ΅: ```ruby response = client.get_order_status_extended(language: 'en', order_number: 'order#1') ``` ```ruby response.data # => # { # "errorCode" => "0", # "errorMessage" => "Success", # "orderNumber" => "order#2", # "orderStatus" => 0, # "actionCode" => -100, # "actionCodeDescription" => "", # "amount" => 1000, # "currency" => "643", # "date" => 1531643056391, # "merchantOrderParams" => [], # "attributes" => [{ "name" => "mdOrder", "value" => "aefeb658-48fb-7f37-aefe-b65804b11830" }], # "terminalId" => "123456", # "paymentAmountInfo" => { "paymentState" => "CREATED", "approvedAmount" => 0, "depositedAmount" => 0, "refundedAmount" => 0}, # "bankInfo" => { "bankCountryCode" => "UNKNOWN", "bankCountryName" => "<Unknown>" } # } response.terminal_id # => "123456" ``` ### ΠΡΠΎΠ²Π΅ΡΠΊΠ° ΠΊΠΎΠ½ΡΡΠΎΠ»ΡΠ½ΠΎΠΉ ΡΡΠΌΠΌΡ callback-ΡΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΠΉ API ΡΠΊΠ²Π°ΠΉΡΠΈΠ½Π³Π° Π‘Π±Π΅ΡΠ±Π°Π½ΠΊΠ° ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅Ρ Π΄Π²Π° Π²ΠΈΠ΄Π° callback-ΡΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΠΉ: Π±Π΅Π· ΠΊΠΎΠ½ΡΡΠΎΠ»ΡΠ½ΠΎΠΉ ΡΡΠΌΠΌΡ ΠΈ Ρ ΠΊΠΎΠ½ΡΡΠΎΠ»ΡΠ½ΠΎΠΉ ΡΡΠΌΠΌΠΎΠΉ. Π ΡΠ»ΡΡΠ°Π΅ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ ΡΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΡ Ρ ΠΊΠΎΠ½ΡΡΠΎΠ»ΡΠ½ΠΎΠΉ ΡΡΠΌΠΌΠΎΠΉ, Π°Π»Π³ΠΎΡΠΈΡΠΌ ΠΏΡΠΎΠ²Π΅ΡΠΊΠΈ Π²ΠΊΠ»ΡΡΠ°Π΅Ρ Π² ΡΠ΅Π±Ρ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Π·Π°ΠΏΡΠΎΡΠ° 'getOrderStatusExtended' ΠΊ API ΡΠΊΠ²Π°ΠΉΡΠΈΠ½Π³Π° Π΄Π»Ρ ΠΏΡΠΎΠ²Π΅ΡΠΊΠΈ Π΄Π΅ΠΉΡΡΠ²ΠΈΡΠ΅Π»ΡΠ½ΠΎΠ³ΠΎ ΡΡΠ°ΡΡΡΠ° ΠΏΠ»Π°ΡΠ΅ΠΆΠ°. Π ΠΎΡΡΠ°Π»ΡΠ½ΡΡ ΡΠ»ΡΡΠ°ΡΡ ΡΡΠ΅Π±ΡΠ΅ΡΡΡ ΠΏΡΠΎΠ²Π΅ΡΠΊΠ° ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠ° `checksum` Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ ΡΠΈΠΌΠΌΠ΅ΡΡΠΈΡΠ½ΠΎΠ³ΠΎ ΠΈΠ»ΠΈ Π°ΡΠΈΠΌΠΌΠ΅ΡΡΠΈΡΠ½ΠΎΠ³ΠΎ ΠΊΠ»ΡΡΠ°. #### Π‘ΠΈΠΌΠΌΠ΅ΡΡΠΈΡΠ½ΡΠΉ ΠΊΠ»ΡΡ ```ruby # params = {} key = '20546026a3675994185a132875efe41a' callback_params = params.dup checksum = callback_params.delete('checksum') validator = Sberbank::Acquiring::SymmetricKeyChecksumValidator.new(key) if validator.validate(checksum, callback_params) # Π·Π°ΠΏΡΠΎΡ ΡΡΠΏΠ΅ΡΠ½ΠΎ ΠΏΡΠΎΡΠ΅Π» Π²Π°Π»ΠΈΠ΄Π°ΡΠΈΡ, ΠΊΠΎΠ½ΡΡΠΎΠ»ΡΠ½Π°Ρ ΡΡΠΌΠΌΠ° Π²Π΅ΡΠ½Π° else # Π·Π°ΠΏΡΠΎΡ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ Π±ΡΡΡ ΠΎΠ±ΡΠ°Π±ΠΎΡΠ°Π½, ΡΠ°ΠΊ ΠΊΠ°ΠΊ ΠΊΠΎΠ½ΡΡΠΎΠ»ΡΠ½Π°Ρ ΡΡΠΌΠΌΠ° Π½Π΅Π²Π΅ΡΠ½Π° end ``` #### ΠΡΠΈΠΌΠΌΠ΅ΡΡΠΈΡΠ½ΡΠΉ ΠΊΠ»ΡΡ ```ruby # params = {} pem = File.read('< ΠΏΡΡΡ Π΄ΠΎ ΡΠ°ΠΉΠ»Π° ΡΠ΅ΡΡΠΈΡΠΈΠΊΠ°ΡΠ° >') callback_params = params.dup checksum = callback_params.delete('checksum') validator = Sberbank::Acquiring::AsymmetricKeyChecksumValidator.new(pem) if validator.validate(checksum, callback_params) # Π·Π°ΠΏΡΠΎΡ ΡΡΠΏΠ΅ΡΠ½ΠΎ ΠΏΡΠΎΡΠ΅Π» Π²Π°Π»ΠΈΠ΄Π°ΡΠΈΡ, ΠΊΠΎΠ½ΡΡΠΎΠ»ΡΠ½Π°Ρ ΡΡΠΌΠΌΠ° Π²Π΅ΡΠ½Π° else # Π·Π°ΠΏΡΠΎΡ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ Π±ΡΡΡ ΠΎΠ±ΡΠ°Π±ΠΎΡΠ°Π½, ΡΠ°ΠΊ ΠΊΠ°ΠΊ ΠΊΠΎΠ½ΡΡΠΎΠ»ΡΠ½Π°Ρ ΡΡΠΌΠΌΠ° Π½Π΅Π²Π΅ΡΠ½Π° end ``` ## Π Π°Π·ΡΠ°Π±ΠΎΡΠΊΠ° ΠΠΎΡΠ»Π΅ ΠΊΠ»ΠΎΠ½ΠΈΡΠΎΠ²Π°Π½ΠΈΡ ΡΠ΅ΠΏΠΎΠ·ΠΈΡΠΎΡΠΈΡ, Π²ΡΠΏΠΎΠ»Π½ΠΈΡΠ΅ `bin/setup` ΡΡΠΎΠ±Ρ ΡΡΡΠ°Π½ΠΎΠ²ΠΈΡΡ Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠΈ. ΠΠ°ΡΠ΅ΠΌ Π²ΡΠΏΠΎΠ»Π½ΠΈΡΠ΅ `rake test`, ΡΡΠΎΠ±Ρ Π·Π°ΠΏΡΡΡΠΈΡΡ ΡΠ΅ΡΡΡ. Π’Π°ΠΊ ΠΆΠ΅ ΠΌΠΎΠΆΠ½ΠΎ Π·Π°ΠΏΡΡΡΠΈΡΡ ΠΈΠ½ΡΠ΅ΡΠ°ΠΊΡΠΈΠ²Π½ΡΡ ΠΊΠΎΠ½ΡΠΎΠ»Ρ Π΄Π»Ρ ΡΠΊΡΠΏΠ΅ΡΠΈΠΌΠ΅Π½ΡΠΎΠ², Π²ΡΠΏΠΎΠ»Π½ΠΈΠ² `bin/console`. ## TODO 1. ΠΠΎΠ±Π°Π²ΠΈΡΡ API Π΄Π»Ρ ΡΠΎΠ³ΠΎ ΡΡΠΎΠ±Ρ ΡΠ΄Π΅Π»Π°ΡΡ ΡΠ΄ΠΎΠ±Π½Π΅Π΅ ΠΎΡΠΏΡΠ°Π²ΠΊΡ Π·Π°ΠΊΠ°Π·ΠΎΠ² ΠΏΠΎ Π€Π€Π 1.05. ΠΡΠΈΠΌΠ΅ΡΠ½ΡΠΉ API: ```ruby sberbank_order = SBRF::Acquiring::Order.new( number: 'order#1', amount: 1, amount_cents: 100, return_url: 'https://', fail_url: 'https://', params: { email: 'email@example.com' }, tax_system: SBRF::USN_INCOME ) item = SBRF::Acquiring::Item.new( name: 'item#1', quantity: 2, measure: 'pcs', price: 1, code: 'item#1', tax: SBRF::VAT0) item.tax = SBRF::VAT18 item.to_h #=> { name: '', quantity: 2. ... amount: 200, tax: { tax_type: 3, tax_sum: 36 } } sberbank_order.items << item ``` ## Contributing Bug reports and pull requests are welcome on GitHub at https://github.com/panasyuk/sberbank-acquiring. ## License The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).