payanyway 1.0.0 → 1.2.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 257f313795dce5796dc66612f46fa949cdb20e0c
4
- data.tar.gz: f6fb7fdec9464461c7b33fa81a0857eead5f83f5
3
+ metadata.gz: a3820acaab28d06906f0eb283beda473a1d2f084
4
+ data.tar.gz: 0e8f58b5347aea043c3ee8a17fc346afbb078d43
5
5
  SHA512:
6
- metadata.gz: 9e0de6dff4b65949d18b709cd12e7ba6f1ebf78927736b224d4b818b81c96b1ff33558688dcd8bf8058a932f2cc6e01f4b8c7d101757c6f0f041befccc3f9274
7
- data.tar.gz: 4af175a8d83770dc55017f5866c3243ebe179a8bea4ce743beca6ab41841ef91f32e2403c2719cd2fb434c79e36a038bbcdcfaf480bbeed4e927f003952fb8ff
6
+ metadata.gz: dbb2e8812b3d2d95fb3cdc87d23ad119600c763fffc19891980a9e5c681aeabfffa8ed63921b1ca9cae8d00aa8a7b301276951a671819b116eb539de353cb542
7
+ data.tar.gz: 8b4c4f979d6adf934788cb5fbf542b9288615cffd32c720f5682022b4f6ef66d49c94bf51802865acc23973460c646b1648a78b931c2b062041171faa9dc3caf
data/README.md CHANGED
@@ -44,7 +44,7 @@ class PayanywayController
44
44
 
45
45
  def pay_implementation(params)
46
46
  # вызывается при оповещении магазина об
47
- # успешной оплате пользователем заказа.
47
+ # успешной оплате пользователем заказа. (Pay URL)
48
48
  #
49
49
  # params[ KEY ], где KEY ∈ [ :moneta_id, :order_id, :operation_id,
50
50
  # :amount, :currency, :subscriber_id, :test_mode, :user, :corraccount,
@@ -54,6 +54,23 @@ class PayanywayController
54
54
  def fail_implementation(order_id)
55
55
  # вызывается при отправки шлюзом пользователя на Fail URL.
56
56
  end
57
+
58
+ def return_implementation(order_id)
59
+ # Вызывается при добровольном отказе пользователем от оплаты (Return URL)
60
+ end
61
+
62
+ def in_progress_implementation(order_id)
63
+ # Вызывается после успешного запроса на авторизацию средств,
64
+ # до подтверждения списания и зачисления средств (InProgress URL)
65
+ #
66
+ # ВНИМАНИЕ: InProgress URL может быть использован в любом способе оплаты.
67
+ # Если к моменту, когда пользователя надо вернуть в магазин оплата
68
+ # по какой-либо причине не завершена, то его перекинет на InProgress, если он указан.
69
+ # Если InProgress URL не указан, то на Success URL.
70
+ # Если операция уже успешно выполнилась, то сразу на Success URL.
71
+ # К примеру, в случае с картами чаще всего получается так, что операция не успевает выполниться,
72
+ # поэтому InProgress будет использован с бОльшей вероятностью, чем Success URL.
73
+ end
57
74
  end
58
75
  ```
59
76
 
@@ -73,7 +90,12 @@ production: <<: *config
73
90
  ```
74
91
  ## Использование
75
92
 
76
- Что бы получить ссылку на платежный шлюз для оплаты заказа пользвателем, используйте `Payanyway::Gateway.payment_url(params, use_signature = true)`, где `params[ KEY ]` такой, что `KEY` ∈ `[:order_id, :amount, :test_mode, :description, :subscriber_id, :custom1, :custom2, :custom3]`
93
+ Что бы получить ссылку на платежный шлюз для оплаты заказа пользвателем,
94
+ используйте `Payanyway::Gateway.payment_url(params, use_signature = true)`, где `params[ KEY ]` такой, что `KEY` ∈
95
+ `[:order_id, :amount, :test_mode, :description, :subscriber_id, :custom1, :custom2, :custom3, :locale, :payment_system_unit_id, :payment_system_limit_ids]`
96
+
97
+ Если в настройках счета в системе **moneta.ru** выставлен флаг «Можно переопределять настройки в URL», то можно так же передавать
98
+ `[:success_url, :in_progress_url, :fail_url, :return_url]`.
77
99
 
78
100
  Пример:
79
101
  ```ruby
@@ -84,7 +106,9 @@ class OrdersController < AplicationController
84
106
  order = Order.create(params[:order])
85
107
  redirect_to Payanyway::Gateway.payment_url(
86
108
  order_id: order.id,
87
- amount: order.total_amount
109
+ amount: order.total_amount,
110
+ locale: 'ru',
111
+ description: "Оплата заказа № #{ order.number } на сумму #{ order.total_amount }руб."
88
112
  )
89
113
  end
90
114
  end
@@ -93,18 +117,26 @@ end
93
117
  ### Расшифровка параметров
94
118
 
95
119
  params[ KEY ], где KEY | Описание
96
- --------------------------|:-----------------------------------------------------------
97
- `:moneta_id` | Идентификатор магазина в системе MONETA.RU.
98
- `:order_id` | Внутренний идентификатор заказа, однозначно определяющий заказ в магазине.
99
- `:operation_id` | Номер операции в системе MONETA.RU.
100
- `:amount` | Фактическая сумма, полученная на оплату заказа.
101
- `:currency` | ISO код валюты, в которой произведена оплата заказа в магазине.
102
- `:test_mode` | Флаг оплаты в тестовом режиме (1 - да, 0 - нет).
103
- `description` | Описание оплаты.
104
- `:subscriber_id` | Внутренний идентификатор пользователя в системе магазина.
105
- `:corraccount` | Номер счета плательщика.
106
- `:custom[1|2|3]` | Поля произвольных параметров. Будут возращены магазину в параметрах отчета о проведенной оплате.
107
- `:user` | Номер счета пользователя, если оплата производилась с пользовательского счета в системе «MONETA.RU».MONETA.Assistant.
120
+ ---------------------------|:-----------------------------------------------------------
121
+ `:moneta_id` | Идентификатор магазина в системе MONETA.RU.
122
+ `:order_id` | Внутренний идентификатор заказа, однозначно определяющий заказ в магазине.
123
+ `:operation_id` | Номер операции в системе MONETA.RU.
124
+ `:amount` | Фактическая сумма, полученная на оплату заказа.
125
+ `:currency` | ISO код валюты, в которой произведена оплата заказа в магазине.
126
+ `:test_mode` | Флаг оплаты в тестовом режиме (1 - да, 0 - нет).
127
+ `:description` | Описание оплаты.
128
+ `:subscriber_id` | Внутренний идентификатор пользователя в системе магазина.
129
+ `:corraccount` | Номер счета плательщика.
130
+ `:custom[1|2|3]` | Поля произвольных параметров. Будут возращены магазину в параметрах отчета о проведенной оплате.
131
+ `:user` | Номер счета пользователя, если оплата производилась с пользовательского счета в системе «MONETA.RU».MONETA.Assistant.
132
+ `:locale` | (ru\|en) Язык пользовательского интерфейса.
133
+ `:payment_system_unit_id` | Предварительный выбор платежной системы. (https://www.moneta.ru/viewPaymentMethods.htm)
134
+ `:payment_system_limit_ids`| Список (разделенный запятыми) идентификаторов платежных систем, которые необходимо показывать пользователю.
135
+ `:success_url` | URL страницы магазина, куда должен попасть покупатель после успешно выполненных действий.
136
+ `:in_progress_url` | URL страницы магазина, куда должен попасть покупатель после успешного запроса на авторизацию средств, до подтверждения списания и зачисления средств.
137
+ `:fail_url` | URL страницы магазина, куда должен попасть покупатель после отмененной или неуспешной оплаты.
138
+ `:return_url` | URL страницы магазина, куда должен вернуться покупатель при добровольном отказе от оплаты.
139
+
108
140
 
109
141
  ## Contributing
110
142
 
data/config/routes.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  Payanyway::Engine.routes.draw do
2
- get 'success' => 'payanyway#success', as: :payanyway_on_success
3
- get 'pay' => 'payanyway#pay', as: :payanyway_pay
4
- get 'fail' => 'payanyway#fail', as: :payanyway_on_fail
5
- end
2
+ get 'success' => 'payanyway#success', as: :payanyway_on_success
3
+ get 'pay' => 'payanyway#pay', as: :payanyway_pay
4
+ get 'fail' => 'payanyway#fail', as: :payanyway_on_fail
5
+ get 'return' => 'payanyway#return', as: :payanyway_on_return
6
+ get 'in_progress' => 'payanyway#in_progress', as: :payanyway_in_progress
7
+ get 'check' => 'payanyway#check', as: :payanyway_on_check
8
+ end
data/lib/payanyway.rb CHANGED
@@ -4,6 +4,10 @@ require 'active_support/core_ext'
4
4
  require 'payanyway/helpers/settings'
5
5
  require 'payanyway/helpers/signature_generator'
6
6
 
7
+ require 'payanyway/request/payment_url'
8
+ require 'payanyway/response/base'
9
+ require 'payanyway/response/pay'
10
+
7
11
  require 'payanyway/gateway'
8
12
  require 'payanyway/engine'
9
13
  require 'payanyway/controller'
@@ -8,49 +8,84 @@ module Payanyway
8
8
 
9
9
  def pay
10
10
  service = Payanyway::Response::Pay.new(params)
11
- service.perform
12
11
  service.success? ?
13
12
  pay_implementation(service.pretty_params) :
14
- error_log(service.pretty_params)
13
+ Rails.logger.error(service.error_message)
15
14
 
16
15
  render text: service.result
17
16
  end
18
17
 
19
18
  def success
20
19
  service = Payanyway::Response::Base.new(params)
21
- Rails.logger.info("Called success payment url for order '#{ service.pretty_params[:order_id] }'")
22
20
 
23
21
  success_implementation(service.pretty_params)
24
22
  end
25
23
 
26
24
  def fail
27
25
  service = Payanyway::Response::Base.new(params)
28
- Rails.logger.error("Fail paid order '#{ service.pretty_params[:order_id] }'")
29
26
 
30
- fail_implementation(service.pretty_params)
27
+ fail_implementation(service.pretty_params[:order_id])
31
28
  end
32
29
 
33
- private
30
+ def return
31
+ service = Payanyway::Response::Base.new(params)
32
+
33
+ return_implementation(service.pretty_params[:order_id])
34
+ end
35
+
36
+ def in_progress
37
+ service = Payanyway::Response::Base.new(params)
34
38
 
35
- def error_log(params)
36
- Rails.logger.error("ERROR! Invalid signature for order #{ params[:order_id] }. Params: #{ params.inspect }")
39
+ in_progress_implementation(service.pretty_params[:order_id])
37
40
  end
38
41
 
42
+ def check
43
+ service = Payanyway::Response::Check.new(params)
44
+ raise service.error_message unless service.success?
45
+
46
+ render xml: service.result(check_implementation(service.pretty_params)).to_xml
47
+ end
48
+
49
+ private
50
+
39
51
  def pay_implementation(params)
40
52
  # Вызывается после успешного прохождения
41
53
  # запроса об оплате от payanyway.ru
42
54
 
43
- Rails.logger.info("Success paid order #{ params[:order_id] }")
55
+ Rails.logger.info("PAYANYWAY: Success paid order #{ params[:order_id] }")
44
56
  end
45
57
 
46
58
  def success_implementation(params)
47
59
  # Вызывается после успешной оплаты
60
+
61
+ Rails.logger.info("PAYANYWAY: Called success payment url for order '#{ params[:order_id] }'")
48
62
  render nothing: true
49
63
  end
50
64
 
51
- def fail_implementation(params)
65
+ def fail_implementation(order_id)
52
66
  # Вызывается после ошибки при оплате
67
+
68
+ Rails.logger.error("PAYANYWAY: Fail paid order '#{ order_id }'")
69
+ render nothing: true
70
+ end
71
+
72
+ def return_implementation(order_id)
73
+ # Вызывается при добровольном отказе пользователем от оплаты
74
+
75
+ Rails.logger.info("PAYANYWAY: Return from payanyway. Order '#{ order_id }'")
53
76
  render nothing: true
54
77
  end
78
+
79
+ def in_progress_implementation(order_id)
80
+ # Вызывается после успешного запроса на авторизацию средств, до подтверждения списания и зачисления средств
81
+
82
+ Rails.logger.info("PAYANYWAY: Order '#{ order_id }' in progress")
83
+ render nothing: true
84
+ end
85
+
86
+ def check_implementation(params)
87
+ # Ответ на запрос о проверке заказа
88
+ # { amount: AMOUNT, state: STATE, description: description, attributes: ATTRIBUTES }
89
+ end
55
90
  end
56
91
  end
@@ -35,8 +35,19 @@ module Payanyway
35
35
  # * _params[custom1]_ - Поля произвольных параметров.
36
36
  # * _params[custom2]_ - Поля произвольных параметров.
37
37
  # * _params[custom3]_ - Поля произвольных параметров.
38
+ # * _params[locale]_ - (ru|en) Язык пользовательского интерфейса.
38
39
 
39
- Payanyway::Helpers::PaymentUrl.build(params, use_signature)
40
+ # * _params[payment_system_unit_id ]_ - Предварительный выбор платежной системы. (https://www.moneta.ru/viewPaymentMethods.htm)
41
+ # * _params[payment_system_limit_ids ]_ - Список (разделенный запятыми) идентификаторов платежных систем, которые необходимо показывать пользователю. (https://www.moneta.ru/viewPaymentMethods.htm)
42
+
43
+ # Эти параметры используются только тогда, когда в настройках счета выставлен флаг «Можно переопределять настройки в URL»
44
+ # * _params[success_url]_ - URL страницы магазина, куда должен попасть покупатель после успешно выполненных действий.
45
+ # * _params[inprogress_url]_- URL страницы магазина, куда должен попасть покупатель после успешного запроса на авторизацию средств, до подтверждения списания и зачисления средств.
46
+ # * _params[fail_url]_ - URL страницы магазина, куда должен попасть покупатель после отмененной или неуспешной оплаты.
47
+ # * _params[return_url]_ - URL страницы магазина, куда должен вернуться покупатель при добровольном отказе от оплаты.
48
+
49
+
50
+ Payanyway::Request::PaymentUrl.build(params, use_signature)
40
51
  end
41
52
 
42
53
  class << self
@@ -3,27 +3,29 @@ require 'digest/md5'
3
3
  module Payanyway
4
4
  module Helpers
5
5
  class SignatureGenerate
6
- class << self
7
- PAY_KEYS = %w(
8
- MNT_TRANSACTION_ID
9
- MNT_OPERATION_ID
10
- MNT_AMOUNT
11
- MNT_CURRENCY_CODE
12
- MNT_SUBSCRIBER_ID
13
- MNT_TEST_MODE
14
- )
15
-
16
- URL_KEYS = PAY_KEYS - [ 'MNT_OPERATION_ID' ]
17
-
18
- def for_pay(params)
19
- generate_by(params, PAY_KEYS)
20
- end
21
-
22
-
23
- def for_url(params)
24
- generate_by(params, URL_KEYS)
6
+ BASE_KEYS = %w(
7
+ MNT_TRANSACTION_ID
8
+ MNT_OPERATION_ID
9
+ MNT_AMOUNT
10
+ MNT_CURRENCY_CODE
11
+ MNT_SUBSCRIBER_ID
12
+ MNT_TEST_MODE
13
+ )
14
+
15
+ KEYS = {
16
+ pay: BASE_KEYS,
17
+ url: BASE_KEYS - [ 'MNT_OPERATION_ID' ],
18
+ check: [ 'MNT_COMMAND' ] + BASE_KEYS,
19
+ check_response: %w(MNT_RESULT_CODE MNT_ID MNT_TRANSACTION_ID)
20
+ }
21
+
22
+ KEYS.each do |key_name, keys|
23
+ define_singleton_method("for_#{ key_name }") do |params|
24
+ generate_by(params, keys)
25
25
  end
26
+ end
26
27
 
28
+ class << self
27
29
  private
28
30
 
29
31
  def generate_by(params, keys)
@@ -33,7 +35,7 @@ module Payanyway
33
35
  end
34
36
 
35
37
  def get_value(params, key)
36
- (key == 'MNT_AMOUNT') ? '%.2f' % params[key] : params[key]
38
+ (key == 'MNT_AMOUNT' && params[key].present?) ? '%.2f' % params[key] : params[key]
37
39
  end
38
40
 
39
41
  def md5(str)
@@ -1,15 +1,25 @@
1
1
  module Payanyway
2
- module Helpers
2
+ module Request
3
3
  class PaymentUrl
4
4
  PARAMS = {
5
- 'MNT_TRANSACTION_ID' => :order_id,
6
- 'MNT_DESCRIPTION' => :description,
7
- 'MNT_SUBSCRIBER_ID' => :subscriber_id,
8
- 'MNT_AMOUNT' => :amount,
9
- 'MNT_CUSTOM1' => :custom1,
10
- 'MNT_CUSTOM2' => :custom2,
11
- 'MNT_CUSTOM3' => :custom3
12
- # 'MNT_SIGNATURE' => добавляется при use_signature == true
5
+ 'MNT_TRANSACTION_ID' => :order_id,
6
+ 'MNT_AMOUNT' => :amount,
7
+ 'MNT_DESCRIPTION' => :description,
8
+ 'MNT_SUBSCRIBER_ID' => :subscriber_id,
9
+
10
+ 'MNT_SUCCESS_URL' => :success_url,
11
+ 'MNT_INPROGRESS_URL' => :in_progress_url,
12
+ 'MNT_FAIL_URL' => :fail_url,
13
+ 'MNT_RETURN_URL' => :return_url,
14
+
15
+ 'MNT_CUSTOM1' => :custom1,
16
+ 'MNT_CUSTOM2' => :custom2,
17
+ 'MNT_CUSTOM3' => :custom3,
18
+
19
+ 'moneta.locale' => :locale,
20
+ 'paymentSystem.unitId' => :payment_system_unit_id,
21
+ 'paymentSystem.limitIds' => :payment_system_limit_ids
22
+ # 'MNT_SIGNATURE' => добавляется при use_signature == true
13
23
  }.to_settings
14
24
 
15
25
  class << self
@@ -9,6 +9,10 @@ module Payanyway
9
9
  @params = params
10
10
  @pretty_params = @@_params.configure_by(params)
11
11
  end
12
+
13
+ def error_message
14
+ "ERROR! Invalid signature for order #{ @pretty_params[:order_id] }. Params: #{ @params.inspect }"
15
+ end
12
16
  end
13
17
  end
14
- end
18
+ end
@@ -0,0 +1,113 @@
1
+ module Payanyway
2
+ module Response
3
+ class InvalidState < Exception; end
4
+
5
+ class Check < Base
6
+ RESPONSE_CODE = {
7
+ set_amount: 100,
8
+ paid: 200,
9
+ in_process: 302,
10
+ unpaid: 402,
11
+ canceled: 500
12
+ }
13
+
14
+ @@_params = {
15
+ 'MNT_COMMAND' => :command,
16
+ 'MNT_ID' => :moneta_id,
17
+ 'MNT_TRANSACTION_ID' => :order_id,
18
+ 'MNT_OPERATION_ID' => :operation_id,
19
+ 'MNT_AMOUNT' => :amount,
20
+ 'MNT_CURRENCY_CODE' => :currency,
21
+ 'MNT_SUBSCRIBER_ID' => :subscriber_id,
22
+ 'MNT_TEST_MODE' => :test_mode,
23
+ 'MNT_SIGNATURE' => :signature,
24
+ 'MNT_USER' => :user,
25
+ 'MNT_CORRACCOUNT' => :corraccount,
26
+ 'MNT_CUSTOM1' => :custom1,
27
+ 'MNT_CUSTOM2' => :custom2,
28
+ 'MNT_CUSTOM3' => :custom3,
29
+ 'paymentSystem.unitId' => :payment_system_unit_id
30
+ }.invert.to_settings
31
+
32
+ def initialize(params)
33
+ super
34
+ @valid_signature = (@pretty_params[:signature] == Payanyway::Helpers::SignatureGenerate.for_check(@params))
35
+ end
36
+
37
+ def success?
38
+ @valid_signature
39
+ end
40
+
41
+ def result(attr)
42
+ # Возвращает Nokogiri::XML документ
43
+ # * _attr[:amount] - сумма заказа
44
+ # * _attr[:state] - статус платежа(см. RESPONSE_CODE)
45
+ # * _attr[:description] - Произвольное описание заказа (необязятельно)
46
+ # * _attr[:attributes] - Произвольный атрибуты заказа (необязятельно)
47
+
48
+ validate_status!(attr[:state])
49
+
50
+ xml = base_xml(attr[:amount], attr[:state], attr[:description])
51
+ parent = xml.at_css('MNT_RESPONSE')
52
+
53
+ parent.add_child(signature_node(xml))
54
+ parent.add_child(attributes_node(attr[:attributes], xml)) if attr[:attributes].present?
55
+
56
+ xml
57
+ end
58
+
59
+ private
60
+
61
+ def validate_status!(status)
62
+ if RESPONSE_CODE.keys.exclude?(status.to_sym)
63
+ raise InvalidState.new("PAYANYWAY: Invalid response state! State must be eq #{ RESPONSE_CODE.keys }")
64
+ end
65
+ end
66
+
67
+ def base_xml(amount, state, description)
68
+ xml = <<-EOXML
69
+ <MNT_RESPONSE>
70
+ <MNT_ID>#{ Payanyway::Gateway.config['moneta_id'] }</MNT_ID>
71
+ <MNT_TRANSACTION_ID>#{ @pretty_params[:order_id] }</MNT_TRANSACTION_ID>
72
+ <MNT_RESULT_CODE>#{ result_code_of(amount, state) }</MNT_RESULT_CODE>
73
+ <MNT_DESCRIPTION>#{ description }</MNT_DESCRIPTION>
74
+ <MNT_AMOUNT>#{ amount }</MNT_AMOUNT>
75
+ </MNT_RESPONSE>
76
+ EOXML
77
+
78
+ Nokogiri::XML(xml, nil, 'UTF-8')
79
+ end
80
+
81
+ def signature_node(xml)
82
+ create_new_node('MNT_SIGNATURE',
83
+ Payanyway::Helpers::SignatureGenerate.for_check_response(Hash.from_xml(xml.to_s)['MNT_RESPONSE']),
84
+ xml
85
+ )
86
+ end
87
+
88
+ def result_code_of(amount, state)
89
+ if @pretty_params[:amount].blank? && amount.present?
90
+ RESPONSE_CODE[:set_amount]
91
+ else
92
+ RESPONSE_CODE[state.to_sym]
93
+ end
94
+ end
95
+
96
+ def attributes_node(attributes, xml)
97
+ Nokogiri::XML::Node.new('MNT_ATTRIBUTES', xml).tap do |node|
98
+ attributes.each do |key, value|
99
+ attr_node = Nokogiri::XML::Node.new('ATTRIBUTE', xml)
100
+ attr_node.add_child(create_new_node('KEY', key.to_s, xml))
101
+ attr_node.add_child(create_new_node('VALUE', value.to_s, xml))
102
+
103
+ node.add_child(attr_node)
104
+ end
105
+ end
106
+ end
107
+
108
+ def create_new_node(name, content, xml)
109
+ Nokogiri::XML::Node.new(name, xml).tap { |node| node.content = content }
110
+ end
111
+ end
112
+ end
113
+ end
@@ -17,8 +17,9 @@ module Payanyway
17
17
  'MNT_CUSTOM3' => :custom3
18
18
  }.invert.to_settings
19
19
 
20
- def perform
21
- @valid_signature = (@pretty_params[:signature] == signature)
20
+ def initialize(params)
21
+ super
22
+ @valid_signature = (@pretty_params[:signature] == Payanyway::Helpers::SignatureGenerate.for_pay(@params))
22
23
  end
23
24
 
24
25
  def success?
@@ -1,3 +1,3 @@
1
1
  module Payanyway
2
- VERSION = '1.0.0'
2
+ VERSION = '1.2.0'
3
3
  end
data/payanyway.gemspec CHANGED
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ['lib']
20
20
 
21
21
  spec.add_dependency 'rails', '>= 3.2.0'
22
+ spec.add_dependency 'nokogiri'
22
23
 
23
24
  spec.add_development_dependency 'bundler', '~> 1.7'
24
25
  spec.add_development_dependency 'rake', '~> 10.0'
@@ -16,5 +16,20 @@ describe Payanyway::Engine, type: :routing do
16
16
  controller: 'payanyway',
17
17
  action: 'fail'
18
18
  )}
19
+
20
+ specify { get('/return').should route_to(
21
+ controller: 'payanyway',
22
+ action: 'return'
23
+ )}
24
+
25
+ specify { get('/in_progress').should route_to(
26
+ controller: 'payanyway',
27
+ action: 'in_progress'
28
+ )}
29
+
30
+ specify { get('/check').should route_to(
31
+ controller: 'payanyway',
32
+ action: 'check'
33
+ )}
19
34
  end
20
35
  end
@@ -3,7 +3,7 @@ describe PayanywayController do
3
3
 
4
4
  describe 'GET #success' do
5
5
  it 'should and message to logger' do
6
- expect(Rails.logger).to receive(:info).with("Called success payment url for order '676'")
6
+ expect(Rails.logger).to receive(:info).with("PAYANYWAY: Called success payment url for order '676'")
7
7
 
8
8
  get :success, { 'MNT_TRANSACTION_ID' => 676 }
9
9
  end
@@ -11,9 +11,42 @@ describe PayanywayController do
11
11
 
12
12
  describe 'GET #fail' do
13
13
  it 'should and message to logger' do
14
- expect(Rails.logger).to receive(:error).with("Fail paid order '676'")
14
+ expect(Rails.logger).to receive(:error).with("PAYANYWAY: Fail paid order '676'")
15
15
 
16
16
  get :fail, { 'MNT_TRANSACTION_ID' => 676 }
17
17
  end
18
18
  end
19
- end
19
+
20
+ describe 'GET #return' do
21
+ it 'should and message to logger' do
22
+ expect(Rails.logger).to receive(:info).with("PAYANYWAY: Return from payanyway. Order '676'")
23
+
24
+ get :return, { 'MNT_TRANSACTION_ID' => 676 }
25
+ end
26
+ end
27
+
28
+ describe 'GET #in_progress' do
29
+ it 'should and message to logger' do
30
+ expect(Rails.logger).to receive(:info).with("PAYANYWAY: Order '676' in progress")
31
+
32
+ get :in_progress, { 'MNT_TRANSACTION_ID' => 676 }
33
+ end
34
+ end
35
+
36
+ describe 'GET #check' do
37
+ context 'when invalid signature' do
38
+ it 'should raise error' do
39
+ expect{ get :check }.to raise_error
40
+ end
41
+ end
42
+
43
+ context 'when valid signature' do
44
+ it 'should and message to logger' do
45
+ expect_any_instance_of(Payanyway::Controller).to receive(:check_implementation).and_return({amount: 12, state: :paid})
46
+ get :check, { 'MNT_TRANSACTION_ID' => 676, 'MNT_SIGNATURE' => '79c1c4f41a0a70bb107c976ebba25811' }
47
+
48
+ expect(Nokogiri::XML(response.body).at_css('MNT_RESPONSE')).to be_present
49
+ end
50
+ end
51
+ end
52
+ end
@@ -23,4 +23,4 @@ describe Payanyway::Gateway do
23
23
  it { is_expected.to be_include('MNT_SIGNATURE') }
24
24
  end
25
25
  end
26
- end
26
+ end
@@ -0,0 +1,43 @@
1
+ require 'uri'
2
+
3
+ describe Payanyway::Request::PaymentUrl do
4
+ subject do
5
+ parse_url = URI(described_class.build(params, false))
6
+
7
+ Hash[ URI.decode_www_form(parse_url.query) ]
8
+ end
9
+
10
+ context 'when reset urls' do
11
+ let(:params) {
12
+ {
13
+ amount: '120.25',
14
+ order_id: 'FF790ABCD',
15
+ success_url: 'success_url',
16
+ in_progress_url: 'in_progress_url',
17
+ fail_url: 'fail_url',
18
+ return_url: 'return_url'
19
+ }
20
+ }
21
+
22
+ its(['MNT_SUCCESS_URL']) { is_expected.to eq('success_url') }
23
+ its(['MNT_INPROGRESS_URL']) { is_expected.to eq('in_progress_url') }
24
+ its(['MNT_FAIL_URL']) { is_expected.to eq('fail_url') }
25
+ its(['MNT_RETURN_URL']) { is_expected.to eq('return_url') }
26
+ end
27
+
28
+ context 'when set payment params' do
29
+ let(:params) {
30
+ {
31
+ amount: '120.25',
32
+ order_id: 'FF790ABCD',
33
+ locale: 'ru',
34
+ payment_system_unit_id: '1015',
35
+ payment_system_limit_ids: '1015,1017'
36
+ }
37
+ }
38
+
39
+ its(['moneta.locale']) { is_expected.to eq('ru') }
40
+ its(['paymentSystem.unitId']) { is_expected.to eq('1015') }
41
+ its(['paymentSystem.limitIds']) { is_expected.to eq('1015,1017') }
42
+ end
43
+ end
@@ -0,0 +1,11 @@
1
+ describe Payanyway::Response::Base do
2
+ let(:service) { described_class.new(params) }
3
+ let(:params) { { 'MNT_ID' => 1, 'MNT_AMOUNT' => 10.20 } }
4
+
5
+ describe '#pretty_params' do
6
+ subject { service.pretty_params }
7
+
8
+ its([:moneta_id]) { is_expected.to eq(1) }
9
+ its([:amount]) { is_expected.to eq(10.20) }
10
+ end
11
+ end
@@ -0,0 +1,102 @@
1
+ describe Payanyway::Response::Check do
2
+ RSpec::Matchers.define :be_eq_node do |expected|
3
+ def value_of(node)
4
+ elements = node.children.select { |e| e.instance_of? Nokogiri::XML::Element }
5
+ elements.map { |el| [ el.name, el.children.many? ? value_of(el) : el.children.text ] }
6
+ end
7
+
8
+ match do |actual|
9
+ value_of(actual) == value_of(expected)
10
+ end
11
+ end
12
+
13
+ let(:service) { described_class.new(params) }
14
+ let(:request_amount) { 10.20 }
15
+ let(:params) do
16
+ {
17
+ 'MNT_TRANSACTION_ID' => 2,
18
+ 'MNT_OPERATION_ID' => 3,
19
+ 'MNT_AMOUNT' => request_amount,
20
+ 'MNT_CURRENCY_CODE' => 'RUB',
21
+ 'MNT_TEST_MODE' => 1
22
+ }
23
+ end
24
+
25
+ describe '#result' do
26
+ let(:xml) { service.result(amount: amount, state: state, description: description, attributes: attributes) }
27
+ let(:amount) { request_amount }
28
+ let(:state) { :unpaid }
29
+ let(:description) { 'Заказ создан, но не оплачен' }
30
+ let(:attributes) { {} }
31
+
32
+ context 'when code 402' do
33
+ it 'should valid xml' do
34
+ expected = <<-EOXML
35
+ <MNT_RESPONSE>
36
+ <MNT_ID>141290</MNT_ID>
37
+ <MNT_TRANSACTION_ID>2</MNT_TRANSACTION_ID>
38
+ <MNT_RESULT_CODE>402</MNT_RESULT_CODE>
39
+ <MNT_DESCRIPTION>Заказ создан, но не оплачен</MNT_DESCRIPTION>
40
+ <MNT_AMOUNT>10.2</MNT_AMOUNT>
41
+ <MNT_SIGNATURE>061c2b859c27c75db9e5bbef3aef90a0</MNT_SIGNATURE>
42
+ </MNT_RESPONSE>
43
+ EOXML
44
+ expected_xml = Nokogiri::XML(expected, nil, 'UTF-8')
45
+
46
+ expect(xml.at_css('MNT_RESPONSE')).to be_eq_node(expected_xml.at_css('MNT_RESPONSE'))
47
+ end
48
+ end
49
+
50
+ context 'when have attributes' do
51
+ let(:attributes) { { type: 'chocolate', brand: 'Mars' } }
52
+
53
+ it 'should generate attributes xml' do
54
+ expected = <<-EOXML
55
+ <MNT_RESPONSE>
56
+ <MNT_ATTRIBUTES>
57
+ <ATTRIBUTE>
58
+ <KEY>type</KEY>
59
+ <VALUE>chocolate</VALUE>
60
+ </ATTRIBUTE>
61
+ <ATTRIBUTE>
62
+ <KEY>brand</KEY>
63
+ <VALUE>Mars</VALUE>
64
+ </ATTRIBUTE>
65
+ </MNT_ATTRIBUTES>
66
+ </MNT_RESPONSE>
67
+ EOXML
68
+
69
+ expected_xml = Nokogiri::XML(expected, nil, 'UTF-8')
70
+ expect(xml.at_css('MNT_ATTRIBUTES')).to be_eq_node(expected_xml.at_css('MNT_ATTRIBUTES'))
71
+ end
72
+ end
73
+
74
+ describe 'response code' do
75
+ context 'when invalid status' do
76
+ let(:state) { 'foobar' }
77
+ it 'should raise error' do
78
+ expect { xml }.to raise_error(Payanyway::Response::InvalidState)
79
+ end
80
+ end
81
+
82
+ context 'when set amount' do
83
+ let(:request_amount) { nil }
84
+ let(:amount) { 10.10 }
85
+
86
+ it 'should eq 100' do
87
+ code_node = xml.at_css('MNT_RESULT_CODE')
88
+ expect(code_node.text).to eq('100')
89
+ end
90
+ end
91
+
92
+ context 'when valid status' do
93
+ let(:state) { :paid }
94
+
95
+ it 'should eq 200' do
96
+ code_node = xml.at_css('MNT_RESULT_CODE')
97
+ expect(code_node.text).to eq('200')
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -12,20 +12,9 @@ describe Payanyway::Response::Pay do
12
12
  }
13
13
  end
14
14
 
15
- describe '#pretty_params' do
16
- subject { service.pretty_params }
17
-
18
- its([:moneta_id]) { is_expected.to eq(1) }
19
- its([:amount]) { is_expected.to eq(10.20) }
20
- end
21
-
22
- describe '#perform' do
15
+ describe '#success?' do
23
16
  subject { service.success? }
24
17
 
25
- context 'when success' do
26
- before { service.perform }
27
-
28
- it { is_expected.to be_truthy }
29
- end
18
+ it { is_expected.to be_truthy }
30
19
  end
31
- end
20
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: payanyway
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ssnikolay
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-18 00:00:00.000000000 Z
11
+ date: 2015-03-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - '>='
25
25
  - !ruby/object:Gem::Version
26
26
  version: 3.2.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: nokogiri
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -156,10 +170,11 @@ files:
156
170
  - lib/payanyway/controller.rb
157
171
  - lib/payanyway/engine.rb
158
172
  - lib/payanyway/gateway.rb
159
- - lib/payanyway/helpers/payment_url.rb
160
173
  - lib/payanyway/helpers/settings.rb
161
174
  - lib/payanyway/helpers/signature_generator.rb
175
+ - lib/payanyway/request/payment_url.rb
162
176
  - lib/payanyway/response/base.rb
177
+ - lib/payanyway/response/check.rb
163
178
  - lib/payanyway/response/pay.rb
164
179
  - lib/payanyway/version.rb
165
180
  - payanyway.gemspec
@@ -170,6 +185,9 @@ files:
170
185
  - spec/internal/config/payanyway.yml
171
186
  - spec/lib/payanyway/gateway_spec.rb
172
187
  - spec/lib/payanyway/helpers/signature_generator_spec.rb
188
+ - spec/lib/payanyway/request/payment_url_spec.rb
189
+ - spec/lib/payanyway/response/base_spec.rb
190
+ - spec/lib/payanyway/response/check_spec.rb
173
191
  - spec/lib/payanyway/response/pay_spec.rb
174
192
  - spec/spec_helper.rb
175
193
  homepage: ''
@@ -204,5 +222,8 @@ test_files:
204
222
  - spec/internal/config/payanyway.yml
205
223
  - spec/lib/payanyway/gateway_spec.rb
206
224
  - spec/lib/payanyway/helpers/signature_generator_spec.rb
225
+ - spec/lib/payanyway/request/payment_url_spec.rb
226
+ - spec/lib/payanyway/response/base_spec.rb
227
+ - spec/lib/payanyway/response/check_spec.rb
207
228
  - spec/lib/payanyway/response/pay_spec.rb
208
229
  - spec/spec_helper.rb