webpay_by 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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