webpay_by 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e34e902b083183cc3d8ad2c2f136e8afdcc7e239
4
+ data.tar.gz: c90fa63b5585bf32fc8915dae5162876ff88060d
5
+ SHA512:
6
+ metadata.gz: 3dcdbf2f33cade320a1fedadf67e30f77a713dd451fa5a3364afb1b3657b5676854413231e77c390ea34b4411cdff8756e0d448845c01b26a733e3554f46f9e9
7
+ data.tar.gz: fb83f7a6ae7fb81367c3232ce876b160a6da62efab7c9cd220a00d89405401e4f33003161f39423d4489c434f210828718b48233ab76f987d643b4ba5c17968f
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2018 Bexeiitov Nursultan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,111 @@
1
+ # Гем для работы с webpay.by
2
+
3
+ Гем для работы с платежной системой WebPay для использования в проектах, использующих Ruby (Ruby On Rails, Sinatra и др.).
4
+
5
+ WebPay («Вебпей») – белорусская система электронных платежей компании ООО «ВЭБ ПЭЙ»,
6
+ который позволяет осуществлять безопасные платежи при помощи банковских карт VISA и MasterCard
7
+ в режиме реального времени в любой валюте (BYN, USD, RUB, EUR и т.д.).
8
+
9
+ WebPay™ Sandbox — это самостоятельное Web-приложение, являющееся прототипом реальной системы и предназначенное для
10
+ тестирования и ознакомления с возможностями реальной системы WebPay™.
11
+
12
+ Официальный сайт: https://webpay.by
13
+
14
+ Документация: https://webpay.by/wp-content/uploads/2016/08/WebPay-Developer-Guide-2.1.2_RU.pdf
15
+
16
+ ## Установка
17
+
18
+ Добавьте эту строку в ваш Gemfile:
19
+
20
+ gem 'webpay_by'
21
+
22
+ Затем установите gem, используя bundler:
23
+
24
+ $ bundle
25
+
26
+ Или выполните команду:
27
+
28
+ $ gem install webpay_by
29
+
30
+ ## Использование (примеры с использованием Ruby On Rails)
31
+
32
+ ### Настройка
33
+
34
+ Создаем клиент для работы с Webpay
35
+
36
+ ```ruby
37
+ require 'webpay_by/client'
38
+
39
+ webpay_client = WebpayBy::Client.new(
40
+ secret_key: 'your_secret_key',
41
+ billing_id: '000000001',
42
+ debug_mode: !Rails.env.production?,
43
+ login: 'your_login',
44
+ password: 'your_password'
45
+ )
46
+
47
+ Rails.application.config.webpay_by = webpay_client
48
+ ```
49
+
50
+ Формируем заказ и создаем форму
51
+
52
+ ```ruby
53
+ request = Rails.application.config.webpay_by.request(
54
+ order_id: 'item-1',
55
+ seed: '12.12.2019',
56
+ back_url: product_url,
57
+ notify_url: payments_epay_url,
58
+ items: [{price: 100, name: 'Пополнение счёта', quantity: 1}]
59
+ )
60
+
61
+ @form = request.form
62
+
63
+ ```
64
+ ```slim
65
+ = form_tag @form.action_url, method: @form.request_method, id: 'epay-form', enctype: @form.enctype do
66
+ - @form.fields.each do |key, value|
67
+ = hidden_field_tag key, value
68
+ = submit_tag 'Перейти к пополнению'
69
+ ```
70
+ Важно:
71
+ - В режиме разработки, после подтверждения формы оплаты, система может не принять запрос, ссылаясь на неправильный формат wsb_notify_url или wsb_return_url.
72
+ Это связано с тем, что система валидирует эти поля на реальные домены.
73
+ Локальный сервер localhost:3000 или адреса с доменными зонами .dev, .localhost и т.д работат не будут.
74
+ Поэтому перед созданием формы передайте в заказ параметры notify_url и back_url c валидными адресами.
75
+ - Если у вас в биллинг-аккаунте подключена возможность приема оплаты и через систему ЕРИП,
76
+ то при тестировании платежей максимальная длина имени счета (wsb_order_num) равна 10 символам.
77
+ В реальной среде размер этого поля может измениться в зависимости от ограничений, которые будут установлены системой ЕРИП.
78
+
79
+ После совершения удачного платежа, система WebPay отсылает специально сформированный POST-запрос по адресу,
80
+ указанному в поле wsb_notify_url Интернет-ресурса. В этом запросе содержится информация по платежу.
81
+ Полученную информацию Интернет-ресурс должен проверить в соответствии с требованиями выполнения заказа
82
+ и ответить на запрос кодом: "HTTP/1.0 200 OK".
83
+
84
+
85
+ ```ruby
86
+ answer_hash = params.except(:controller, :action).to_unsafe_h.symbolize_keys
87
+ response = webpay_client.response answer_hash
88
+
89
+ if response.approved?
90
+ user.add_balance response.amount
91
+ end
92
+
93
+ render nothing: true, status: 200
94
+ ```
95
+
96
+ Прежде чем доставить товар (оказать услугу), Интернет-ресурс обязан проверить совершенный покупателем платеж.
97
+ Что такое "подтверждение": когда человек ввел данные карты, нужная сумма только блокируется на ней. Чтобы она
98
+ реально списалась, мы должны сообщить системе Webpay, что услуга оказана и сумму можно списать. Это и есть подтверждение.
99
+ Его нужно делать автоматически, поэтому через cron или аналог надо запускать робота, который будет выбирать
100
+ оплаченные заявки и их подтверджать.
101
+
102
+ ```ruby
103
+ webpay_client = Rails.application.config.webpay_by
104
+ confirmation = webpay_client.confirmation(transaction_id: transaction_id)
105
+ confirmation_response = confirmation.send
106
+
107
+ # Проверяем ответ от системы на подлинность электронной подписи и подтверждения об оплате
108
+ if confirmation_response.approved?
109
+ order.update(confirmed: true)
110
+ end
111
+ ```
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require 'bundler/gem_tasks'
data/lib/webpay_by.rb ADDED
@@ -0,0 +1,11 @@
1
+ require 'webpay_by/version'
2
+
3
+ module WebpayBy
4
+ autoload :Client, 'webpay_by/client'
5
+ autoload :Confirmation, 'webpay_by/confirmation'
6
+ autoload :ConfirmationResponse, 'webpay_by/confirmation_response'
7
+ autoload :Form, 'webpay_by/form'
8
+ autoload :Item, 'webpay_by/item'
9
+ autoload :Request, 'webpay_by/request'
10
+ autoload :Response, 'webpay_by/response'
11
+ end
@@ -0,0 +1,47 @@
1
+ # Клиент для взаимодействия с Webpay. Он предоставляет доступ ко всем возможностям системы онлайн-оплаты.
2
+ # Чтобы создать клиент, вам нужно настроить следующие поля:
3
+ # billing_id - уникальный идентификатор магазина.
4
+ # secret_key - секретный ключ, необходим для формирования электронной подписи каждого Вашего платежа.
5
+ # debug_mode - поле, указывающее на проведение тестовой оплаты. Для работы с тестовой средой укажите true.
6
+ # login - имя пользователя.
7
+ # password - пароль.
8
+ #
9
+ # Пример:
10
+ #
11
+ # webpay_client = WebpayBy::Client.new(
12
+ # secret_key: 'your_secret_key',
13
+ # billing_id: '000000001',
14
+ # debug_mode: ENV.development?,
15
+ # login: 'your_login',
16
+ # password: 'your_password'
17
+ # )
18
+ #
19
+ require 'digest'
20
+
21
+ module WebpayBy
22
+ class Client
23
+ attr_reader :billing_id, :secret_key, :debug_mode, :login, :password
24
+
25
+ alias debug_mode? debug_mode
26
+
27
+ def initialize(billing_id:, secret_key:, debug_mode:, login:, password:)
28
+ @billing_id = billing_id
29
+ @secret_key = secret_key
30
+ @debug_mode = debug_mode
31
+ @login = login
32
+ @password = Digest::MD5.hexdigest password
33
+ end
34
+
35
+ def request(options = {})
36
+ WebpayBy::Request.new options.merge client: self
37
+ end
38
+
39
+ def response(options = {})
40
+ WebpayBy::Response.new options.merge client: self
41
+ end
42
+
43
+ def confirmation(options)
44
+ WebpayBy::Confirmation.new options.merge client: self
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Модель для создания запроса об подтверждении оплаты системе Webpay. Перед созданием заказа обязательно создайте клиента.
4
+ # Прежде чем доставить товар (оказать услугу), Интернет-ресурс обязан проверить совершенный покупателем платеж.
5
+ # Необходимо учитывать, что запрос к тестовой среде необходимо отсылать на адрес https://sandbox.webpay.by, а к реальной среде https://billing.webpay.by
6
+ #
7
+ # Пример:
8
+ #
9
+ # Создаем объект и передаем ему номер транзакции
10
+ # confirmation = webpay_client.confirmation(transaction_id: 'item-1')
11
+ #
12
+ # Создаем пост запрос к банку
13
+ # confirmation.send
14
+ # метод send возвращает объект WebpayBy::ConfirmationResponse, который содержить методы для проверки электронной подписи
15
+ # и подтверждения об оплате
16
+ #
17
+ require 'uri'
18
+ require 'net/https'
19
+ require 'openssl'
20
+
21
+ module WebpayBy
22
+ class Confirmation
23
+ SANDBOX_URL = 'https://sandbox.webpay.by'
24
+ BILLING_URL = 'https://billing.webpay.by'
25
+
26
+ attr_reader :client, :transaction_id
27
+
28
+ def initialize(client:, transaction_id:)
29
+ @client = client
30
+ @transaction_id = transaction_id
31
+ end
32
+
33
+ def url_string
34
+ @client.debug_mode? ? SANDBOX_URL : BILLING_URL
35
+ end
36
+
37
+ # ОТВЕТ ЗА ЗАПРОС НА ПОДТВЕРЖДЕНИЕ: Возвращаемый XML выглядит примерно так (без переносов строк):
38
+ # <?xml version="1.0" encoding="UTF-8"?>
39
+ # <wsb_api_response>
40
+ # <version>1</version>
41
+ # <command>get_transaction</command>
42
+ # <status>success</status>
43
+ # <fields>
44
+ # <transaction_id>123456789</transaction_id>
45
+ # <batch_timestamp>31231231</batch_timestamp>
46
+ # <currency_id>BYN</currency_id>
47
+ # <amount>100</amount>
48
+ # <payment_method>cc</payment_method>
49
+ # <payment_type>4</payment_type>
50
+ # <order_id>584236984</order_id>
51
+ # <order_num>5874129</order_num>
52
+ # <rrn>154789648154</rrn>
53
+ # <wsb_signature>3021e68df9a7200135725c6331369a22</wsb_signature>
54
+ # </fields>
55
+ # </wsb_api_response>
56
+ def send
57
+ xml = clear_xml_string api_request_xml
58
+ response = Net::HTTP.post_form(URI.parse(url_string), {'*API': '', 'API_XML_REQUEST': xml}).body
59
+ WebpayBy::ConfirmationResponse.new confirmation: self, response: response
60
+ end
61
+
62
+ def clear_xml_string(xml_str)
63
+ xml_str.gsub("\n", '').gsub(/\s{2,}/, '').gsub(' <', '<')
64
+ end
65
+
66
+ private
67
+
68
+ # Для проверки платежа при возврате на страницу Интернет-ресурса, указанному в поле wsb_return_url, необходимо выполнить
69
+ # API команду биллинга «get_transaction»
70
+ # Сгенерированный XML выглядит примерно так:
71
+ # <?xml version="1.0" encoding="ISO-8859-1"?>
72
+ # <wsb_api_request>
73
+ # <command>get_transaction</command>
74
+ # <authorization>
75
+ # <username>your_username</username>
76
+ # <password>your_md5_password</password>
77
+ # </authorization>
78
+ # <fields>
79
+ # <transaction_id>123456789</transaction_id>
80
+ # </fields>
81
+ # </wsb_api_request>
82
+ def api_request_xml
83
+ xml = Builder::XmlMarkup.new indent: 2
84
+ xml.instruct! :xml, encoding: 'ISO-8859-1'
85
+ xml.wsb_api_request do |req|
86
+ req.command 'get_transaction'
87
+
88
+ req.authorization do |auth|
89
+ auth.username @client.login
90
+ auth.password @client.password
91
+ end
92
+
93
+ req.fields do |merch|
94
+ merch.transaction_id @transaction_id
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Модель для подтверждении оплаты системе Webpay.
4
+ # Пример:
5
+ #
6
+ # Создаем объект и передаем ему номер транзакции
7
+ # confirmation = webpay_client.confirmation(transaction_id: 'item-1')
8
+ #
9
+ # Создаем пост запрос к банку
10
+ # confirmation_response = confirmation.send
11
+ #
12
+ # Проверяем ответ от системы на подлинность электронной подписи и подтверждения об оплате
13
+ #
14
+ require 'digest'
15
+ require 'active_support/core_ext/hash'
16
+
17
+ module WebpayBy
18
+ class ConfirmationResponse
19
+ PAYMENT_TYPES = {
20
+ 'Completed': 'Завершенная',
21
+ 'Declined': 'Отклоненная',
22
+ 'Pending': 'Вобработке',
23
+ 'Authorized': 'Авторизованная',
24
+ 'Refunded': 'Возвращенная',
25
+ 'System': 'Системная',
26
+ 'Voided': 'Сброшенная после авторизации',
27
+ 'Failed': 'Ошибка в проведении операции',
28
+ 'Partial Voided': 'Частичный сброс',
29
+ 'Recurrent': 'Рекуррентный платеж'
30
+ }
31
+
32
+ # Успешной оплате соответствуют следующие значения: Completed, Authorized, Recurrent
33
+ # Ниже храним в константе их типы
34
+ SUCCESSFUL_TYPE_INDEXES = %w( 1 4 10 )
35
+
36
+ attr_reader :confirmation, :response, :parsed_response
37
+
38
+ def initialize(confirmation:, response:)
39
+ @confirmation = confirmation
40
+ @response = response
41
+ @parsed_response = Hash.from_xml(@response).deep_symbolize_keys rescue {}
42
+ end
43
+
44
+ def wsb_api_response
45
+ @parsed_response[:wsb_api_response] || {}
46
+ end
47
+
48
+ def response_fields
49
+ wsb_api_response[:fields] || {}
50
+ end
51
+
52
+ # Проверка аутентичности XML-документа, пришедшего от банка
53
+ def valid_signature?
54
+ return false unless response_fields.any?
55
+
56
+ signature == response_fields[:wsb_signature]
57
+ end
58
+
59
+ def signature
60
+ signed_fields = %i( transaction_id batch_timestamp currency_id amount payment_method payment_type order_id rrn )
61
+ signed_attrs = response_fields.values_at *signed_fields
62
+ signed_attrs << @confirmation.client.secret_key
63
+ Digest::MD5.hexdigest signed_attrs.join
64
+ end
65
+
66
+ def approved?
67
+ payment_type_index = response_fields[:payment_type]
68
+ valid_signature? && payment_type_index.in?(SUCCESSFUL_TYPE_INDEXES)
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Модель для формирования формы оплаты. Перед созданием заказа обязательно создайте заказ(Wepbay::Request).
4
+ # Для оплаты заказа необходимо сформировать форму со специальными полями, и POST методом перенаправить покупателя на страницу оплаты.
5
+ # Для тестирования необходимо указать адрес https://securesandbox.webpay.by, для совершения реальных платежей − https://payment.webpay.by.
6
+ #
7
+ # Все необходимые поля уже настроены в объекте заказа. Дополнительно можно настроить следующие поля:
8
+ # language_id - идентификатор языка формы оплаты. По умолчанию russian.
9
+ #
10
+ # Пример:
11
+ #
12
+ # request = webpay_client.request(
13
+ # order_id: 'item-1',
14
+ # seed: '12.12.2019',
15
+ # back_url: product_url,
16
+ # notify_url: payments_epay_url,
17
+ # items: [{price: 100, name: 'Пополнение счёта', quantity: 1}]
18
+ # )
19
+ #
20
+ # form = request.form(language_id: 'english')
21
+ #
22
+ module WebpayBy
23
+ class Form
24
+ SANDBOX_URL = 'https://securesandbox.webpay.by'
25
+ LIVE_URL = 'https://payment.webpay.by'
26
+ APP_VERSION = 2
27
+ LANGUAGE_LIST = %w( russian english )
28
+ REQUEST_METHOD = 'post'
29
+ ENCTYPE = 'application/x-www-form-urlencoded'
30
+
31
+ attr_reader :request, :version, :language_id, :request_method, :enctype
32
+
33
+ def initialize(request:, language_id: nil)
34
+ @request = request
35
+ @language_id ||= LANGUAGE_LIST.first
36
+ @version = APP_VERSION
37
+ @request_method = REQUEST_METHOD
38
+ @enctype = ENCTYPE
39
+
40
+ raise "Unsupported language, must be one of #{LANGUAGE_LIST.join ', '}" unless LANGUAGE_LIST.include? @language_id
41
+ end
42
+
43
+ def action_url
44
+ @request.client.debug_mode? ? SANDBOX_URL : LIVE_URL
45
+ end
46
+
47
+ def fields
48
+ fields_with_values = {
49
+ '*scart': '',
50
+ wsb_version: @version,
51
+ wsb_language_id: @language_id,
52
+ wsb_storeid: @request.client.billing_id,
53
+ wsb_order_num: @request.order_id,
54
+ wsb_test: @request.test_mode,
55
+ wsb_currency_id: @request.currency_id,
56
+ wsb_seed: @request.seed,
57
+ wsb_total: @request.total,
58
+ wsb_signature: @request.signature,
59
+ wsb_return_url: @request.back_url,
60
+ wsb_notify_url: @request.notify_url
61
+ }
62
+
63
+ @request.items.each_with_index do |item, i|
64
+ fields_with_values.merge!(
65
+ "wsb_invoice_item_name[#{i}]": item.name,
66
+ "wsb_invoice_item_quantity[#{i}]": item.quantity,
67
+ "wsb_invoice_item_price[#{i}]": item.price
68
+ )
69
+ end
70
+
71
+ fields_with_values.compact
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,22 @@
1
+ # Модель для создания товара для заказа.
2
+ # Чтобы создать товар, вам нужно настроить следующие поля:
3
+ # name - Наименование единицы товара.
4
+ # quantity - Количество единиц товара, целое число, обозначающее, количество единиц товара каждого наименования.
5
+ # price - Цена единицы товара, число, определяющее стоимость каждой единицы товара (BYN, USD, EUR, RUB с 2 знаками после запятой или точки).
6
+ #
7
+ # Пример:
8
+ #
9
+ # WebpayBy::Item.new price: 100, name: 'Пополнение счёта', quantity: 1
10
+ #
11
+ module WebpayBy
12
+ class Item
13
+ attr_reader :name, :quantity, :price, :total
14
+
15
+ def initialize(name:, quantity:, price:)
16
+ @price = price
17
+ @quantity = quantity
18
+ @name = name
19
+ @total = @quantity * @price
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Модель для формирования заказа. Перед созданием заказа обязательно создайте клиента.
4
+ # Чтобы создать заказ, вам нужно настроить следующие поля:
5
+ # seed - случайная последовательность символов , участвующих в формировании электронной подписи заказа.
6
+ # order_id - уникальный идентификатор заказа, присваиваемый магазином.
7
+ # back_url - URL адрес на который возвращается покупатель в случае успешной оплаты.
8
+ # notify_url - данный URL вызывается вне зависимости от того, был ли переход по URL в поле wsb_return_url или нет.
9
+ # items - список товаров к оплате.
10
+ # currency_id - идентификатор валюты. Буквенный трехзначный код валюты согласно ISO4271. По умолчанию BYN(белорусский рубль).
11
+ #
12
+ # Пример:
13
+ #
14
+ # request = webpay_client.request(
15
+ # order_id: 'item-1',
16
+ # seed: '12.12.2019',
17
+ # back_url: product_url,
18
+ # notify_url: payments_epay_url,
19
+ # items: [{price: 100, name: 'Пополнение счёта', quantity: 1}]
20
+ # )
21
+ #
22
+ require 'digest'
23
+
24
+ module WebpayBy
25
+ class Request
26
+ CURRENCIES = %w( BYN USD EUR RUB )
27
+
28
+ attr_reader :client, :seed, :order_id, :currency_id, :back_url, :notify_url, :items
29
+
30
+ def initialize(client:, seed:, order_id:, back_url:, notify_url:, items:, currency_id: nil)
31
+ @client = client
32
+ @order_id = order_id
33
+ @seed = seed
34
+ @currency_id ||= CURRENCIES.first
35
+ @back_url = back_url
36
+ @notify_url = notify_url
37
+ @items = items.map { |item| item.is_a?(WebpayBy::Item) ? item : WebpayBy::Item.new(item) }
38
+
39
+ raise "Unsupported currency, must be one of #{CURRENCIES.join ', '}" unless CURRENCIES.include? @currency_id
40
+ end
41
+
42
+ def total
43
+ @items.map(&:total).sum
44
+ end
45
+
46
+ def test_mode
47
+ @client.debug_mode? ? 1 : 0
48
+ end
49
+
50
+ # Электронная подпись формируется для предотвращения изменений в форме платежа и должна присутствовать в каждой форме заказа.
51
+ # Все заказы без электронной подписи не будут рассматриваться системой WebPay
52
+ def signature
53
+ signed_attrs = [@seed, @client.billing_id, @order_id, test_mode, @currency_id, total, @client.secret_key].join
54
+
55
+ Digest::SHA1.hexdigest signed_attrs
56
+ end
57
+
58
+ def form(options = {})
59
+ WebpayBy::Form.new options.merge request: self
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # После совершения удачного платежа, система WebPay отсылает специально сформированный POST-запрос по адресу,
4
+ # указанному в поле wsb_notify_url Интернет-ресурса. В этом запросе содержится информация по платежу.
5
+ # Полученную информацию Интернет-ресурс должен проверить в соответствии с требованиями выполнения заказа
6
+ # и ответить на запрос кодом: "HTTP/1.0 200 OK".
7
+ # Это модель служит для работы с полученные от системы запросом. Перед созданием заказа обязательно создайте клиента.
8
+ # Поля содержащиеся в запросе:
9
+ # batch_timestamp - время совершения транзакции.
10
+ # currency_id - валюта транзакции.
11
+ # amount - сумма транзакции.
12
+ # payment_method - метод совершения транзакции.
13
+ # order_id - номер заказа в системе WebPay.
14
+ # site_order_id - номер (имя) заказа, присвоенное магазином.
15
+ # transaction_id - номер транзакции.
16
+ # payment_type - тип транзакции.
17
+ # rrn - номер транзакции в системе Visa/MasterCard.
18
+ # wsb_signature - электронная подпись.
19
+ #
20
+ # Пример:
21
+ #
22
+ # response = webpay_client.response request.params
23
+ # response.valid_signature?
24
+ #
25
+ require 'digest'
26
+
27
+ module WebpayBy
28
+ class Response
29
+ SUCCESSFUL_TYPE_INDEXES = %w( 1 4 )
30
+
31
+ attr_reader :client, :batch_timestamp, :currency_id, :amount, :payment_method, :order_id, :site_order_id,
32
+ :transaction_id, :payment_type, :rrn
33
+
34
+ def initialize(options = {})
35
+ @client = options[:client]
36
+ @batch_timestamp = options[:batch_timestamp]
37
+ @currency_id = options[:currency_id]
38
+ @amount = options[:amount]
39
+ @payment_method = options[:payment_method]
40
+ @order_id = options[:order_id]
41
+ @site_order_id = options[:site_order_id]
42
+ @transaction_id = options[:transaction_id]
43
+ @payment_type = options[:payment_type]
44
+ @rrn = options[:rrn]
45
+ @wsb_signature = options[:wsb_signature]
46
+ end
47
+
48
+ def approved?
49
+ valid_signature? && @payment_type.in?(SUCCESSFUL_TYPE_INDEXES)
50
+ end
51
+
52
+ # wsb_signature представляет собой hex-последовательность и является результатом выполнения функции MD 5.
53
+ # В качестве аргумента функции MD5 служит текстовая последовательность, полученная путем простой конкатенации
54
+ def valid_signature?
55
+ @wsb_signature.to_s == signature
56
+ end
57
+
58
+ def signature
59
+ signed_attrs = [@batch_timestamp, @currency_id, @amount, @payment_method, @order_id, @site_order_id,
60
+ @transaction_id, @payment_type, @rrn, @client.secret_key].join
61
+
62
+ Digest::MD5.hexdigest signed_attrs
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,3 @@
1
+ module WebpayBy
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,83 @@
1
+ require 'spec_helper'
2
+ require './lib/webpay_by'
3
+
4
+ describe WebpayBy::Client do
5
+ let(:webpay_client) do
6
+ WebpayBy::Client.new(
7
+ secret_key: 'your_secret_key',
8
+ billing_id: '000000001',
9
+ debug_mode: true,
10
+ login: 'your_login',
11
+ password: 'your_password'
12
+ )
13
+ end
14
+
15
+ describe 'Формирования заказа' do
16
+ it 'сгенерирует правильную электронную подпись' do
17
+ request = webpay_client.request(
18
+ order_id: 'item-1',
19
+ seed: '12.12.2019',
20
+ back_url: 'test.com',
21
+ notify_url: 'test.com/notify',
22
+ items: [{price: 100, name: 'Пополнение счёта', quantity: 1}]
23
+ )
24
+
25
+ # seed='12.12.2019' billing_id='000000001' order_id='item-1' test_mode=1 currency_id'BYN'
26
+ # amount=100 secret_key='your_secret_key'
27
+ valid_signature = '42fc5bd5f26360789488073d2d8e535f9e16e2f9'
28
+
29
+ expect(request.signature).to eq valid_signature
30
+ end
31
+ end
32
+
33
+ describe 'Ответ банка' do
34
+ it 'возвращает валидную электронную подпись' do
35
+ answer_params = {
36
+ batch_timestamp: '10.10.2019',
37
+ currency_id: 'BYN',
38
+ amount: '100',
39
+ payment_method: 'cc',
40
+ order_id: '1111',
41
+ site_order_id: 'item-1',
42
+ transaction_id: '1',
43
+ payment_type: '4',
44
+ rrn: '01',
45
+ wsb_signature: '62a2ab40e7ae1630883e1f8e2f284f8a'
46
+ }
47
+
48
+ response = webpay_client.response answer_params
49
+
50
+ expect(response.signature).to eq answer_params[:wsb_signature]
51
+ end
52
+ end
53
+
54
+ describe 'Подтверждения об оплате банку' do
55
+ it 'ответ возвращает валидную электронную подпись' do
56
+ xml_response = <<-XML.gsub("\n", '').gsub(/\s{2,}/, '').gsub(' <', '<')
57
+ <?xml version="1.0" encoding="UTF-8"?>
58
+ <wsb_api_response>
59
+ <version>1</version>
60
+ <command>get_transaction</command>
61
+ <status>success</status>
62
+ <fields>
63
+ <transaction_id>1</transaction_id>
64
+ <batch_timestamp>31231231</batch_timestamp>
65
+ <currency_id>BYN</currency_id>
66
+ <amount>100</amount>
67
+ <payment_method>cc</payment_method>
68
+ <payment_type>4</payment_type>
69
+ <order_id>item-1</order_id>
70
+ <order_num>1111</order_num>
71
+ <rrn>1</rrn>
72
+ <wsb_signature>7f0276873ce8e701c6fe36912fe5fb33</wsb_signature>
73
+ </fields>
74
+ </wsb_api_response>
75
+ XML
76
+
77
+ confirmation = webpay_client.confirmation(transaction_id: '1')
78
+ confirmation_response = WebpayBy::ConfirmationResponse.new(confirmation: confirmation, response: xml_response)
79
+
80
+ expect(confirmation_response.signature).to eq confirmation_response.response_fields[:wsb_signature]
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,17 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ RSpec.configure do |config|
8
+ config.treat_symbols_as_metadata_keys_with_true_values = true
9
+ config.run_all_when_everything_filtered = true
10
+ config.filter_run :focus
11
+
12
+ # Run specs in random order to surface order dependencies. If you find an
13
+ # order dependency and want to debug it, you can fix the order by providing
14
+ # the seed, which is printed after each run.
15
+ # --seed 1234
16
+ config.order = 'random'
17
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: webpay_by
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Bexeiitov Nursultan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-01-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 4.1.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 4.1.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: builder
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Adds the ability to work with the payment system webpay.by.
56
+ email:
57
+ - bekseitov@mail.ru
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - MIT-LICENSE
63
+ - README.md
64
+ - Rakefile
65
+ - lib/webpay_by.rb
66
+ - lib/webpay_by/client.rb
67
+ - lib/webpay_by/confirmation.rb
68
+ - lib/webpay_by/confirmation_response.rb
69
+ - lib/webpay_by/form.rb
70
+ - lib/webpay_by/item.rb
71
+ - lib/webpay_by/request.rb
72
+ - lib/webpay_by/response.rb
73
+ - lib/webpay_by/version.rb
74
+ - spec/models/webpay_by_spec.rb
75
+ - spec/spec_helper.rb
76
+ homepage: http://neoweb.kz
77
+ licenses: []
78
+ metadata: {}
79
+ post_install_message:
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '2.3'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubyforge_project:
95
+ rubygems_version: 2.6.12
96
+ signing_key:
97
+ specification_version: 4
98
+ summary: webpay.by gem
99
+ test_files:
100
+ - spec/models/webpay_by_spec.rb
101
+ - spec/spec_helper.rb