payneteasy-payneteasyapi 0.1.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.
Files changed (87) hide show
  1. data/.gemtest +0 -0
  2. data/Gemfile +3 -0
  3. data/Gemfile.lock +18 -0
  4. data/README.md +54 -0
  5. data/Rakefile +8 -0
  6. data/doc/00-basic-tutorial.md +254 -0
  7. data/doc/01-library-internals.md +6 -0
  8. data/doc/02-payment-scenarios.md +9 -0
  9. data/doc/library-internals/00-payment-data.md +162 -0
  10. data/doc/library-internals/01-payment-processor.md +163 -0
  11. data/doc/library-internals/02-validator.md +55 -0
  12. data/doc/library-internals/03-property-accessor.md +76 -0
  13. data/doc/payment-scenarios/00-sale-transactions.md +90 -0
  14. data/doc/payment-scenarios/01-preauth-capture-transactions.md +105 -0
  15. data/doc/payment-scenarios/02-transfer-transactions.md +89 -0
  16. data/doc/payment-scenarios/03-return-transactions.md +52 -0
  17. data/doc/payment-scenarios/04-recurrent-transactions.md +110 -0
  18. data/doc/payment-scenarios/05-payment-form-integration.md +59 -0
  19. data/doc/payment-scenarios/06-merchant-callbacks.md +29 -0
  20. data/example/capture.rb +12 -0
  21. data/example/common/functions.rb +56 -0
  22. data/lib/paynet_easy/paynet_easy_api/callback/callback_factory.rb +47 -0
  23. data/lib/paynet_easy/paynet_easy_api/callback/callback_prototype.rb +186 -0
  24. data/lib/paynet_easy/paynet_easy_api/callback/customer_return_callback.rb +28 -0
  25. data/lib/paynet_easy/paynet_easy_api/callback/paynet_easy_callback.rb +44 -0
  26. data/lib/paynet_easy/paynet_easy_api/error/paynet_error.rb +4 -0
  27. data/lib/paynet_easy/paynet_easy_api/error/request_error.rb +6 -0
  28. data/lib/paynet_easy/paynet_easy_api/error/response_error.rb +6 -0
  29. data/lib/paynet_easy/paynet_easy_api/error/validation_error.rb +6 -0
  30. data/lib/paynet_easy/paynet_easy_api/payment_data/billing_address.rb +41 -0
  31. data/lib/paynet_easy/paynet_easy_api/payment_data/credit_card.rb +32 -0
  32. data/lib/paynet_easy/paynet_easy_api/payment_data/customer.rb +35 -0
  33. data/lib/paynet_easy/paynet_easy_api/payment_data/data.rb +13 -0
  34. data/lib/paynet_easy/paynet_easy_api/payment_data/payment.rb +190 -0
  35. data/lib/paynet_easy/paynet_easy_api/payment_data/payment_transaction.rb +188 -0
  36. data/lib/paynet_easy/paynet_easy_api/payment_data/query_config.rb +95 -0
  37. data/lib/paynet_easy/paynet_easy_api/payment_data/recurrent_card.rb +40 -0
  38. data/lib/paynet_easy/paynet_easy_api/payment_processor.rb +251 -0
  39. data/lib/paynet_easy/paynet_easy_api/paynet_easy_api.rb +26 -0
  40. data/lib/paynet_easy/paynet_easy_api/query/capture_query.rb +30 -0
  41. data/lib/paynet_easy/paynet_easy_api/query/create_card_ref_query.rb +78 -0
  42. data/lib/paynet_easy/paynet_easy_api/query/get_card_info_query.rb +49 -0
  43. data/lib/paynet_easy/paynet_easy_api/query/make_rebill_query.rb +37 -0
  44. data/lib/paynet_easy/paynet_easy_api/query/preauth_form_query.rb +10 -0
  45. data/lib/paynet_easy/paynet_easy_api/query/preauth_query.rb +10 -0
  46. data/lib/paynet_easy/paynet_easy_api/query/prototype/payment_form_query.rb +69 -0
  47. data/lib/paynet_easy/paynet_easy_api/query/prototype/payment_query.rb +71 -0
  48. data/lib/paynet_easy/paynet_easy_api/query/prototype/query.rb +302 -0
  49. data/lib/paynet_easy/paynet_easy_api/query/query_factory.rb +19 -0
  50. data/lib/paynet_easy/paynet_easy_api/query/return_query.rb +46 -0
  51. data/lib/paynet_easy/paynet_easy_api/query/sale_form_query.rb +10 -0
  52. data/lib/paynet_easy/paynet_easy_api/query/sale_query.rb +53 -0
  53. data/lib/paynet_easy/paynet_easy_api/query/status_query.rb +50 -0
  54. data/lib/paynet_easy/paynet_easy_api/query/transfer_by_ref_query.rb +41 -0
  55. data/lib/paynet_easy/paynet_easy_api/query/transfer_form_query.rb +10 -0
  56. data/lib/paynet_easy/paynet_easy_api/transport/callback_response.rb +21 -0
  57. data/lib/paynet_easy/paynet_easy_api/transport/gateway_client.rb +91 -0
  58. data/lib/paynet_easy/paynet_easy_api/transport/request.rb +20 -0
  59. data/lib/paynet_easy/paynet_easy_api/transport/response.rb +136 -0
  60. data/lib/paynet_easy/paynet_easy_api/util/property_accessor.rb +60 -0
  61. data/lib/paynet_easy/paynet_easy_api/util/string.rb +9 -0
  62. data/lib/paynet_easy/paynet_easy_api/util/validator.rb +110 -0
  63. data/payneteasy-payneteasyapi.gemspec +16 -0
  64. data/test/paynet_easy/paynet_easy_api/callback/callback_factory_test.rb +22 -0
  65. data/test/paynet_easy/paynet_easy_api/callback/callback_test_prototype.rb +168 -0
  66. data/test/paynet_easy/paynet_easy_api/callback/customer_return_callback_test.rb +95 -0
  67. data/test/paynet_easy/paynet_easy_api/callback/paynet_easy_callback_test.rb +101 -0
  68. data/test/paynet_easy/paynet_easy_api/fake.rb +71 -0
  69. data/test/paynet_easy/paynet_easy_api/payment_processor_test.rb +255 -0
  70. data/test/paynet_easy/paynet_easy_api/query/capture_query_test.rb +48 -0
  71. data/test/paynet_easy/paynet_easy_api/query/create_card_ref_query_test.rb +116 -0
  72. data/test/paynet_easy/paynet_easy_api/query/get_card_info_query_test.rb +116 -0
  73. data/test/paynet_easy/paynet_easy_api/query/make_rebill_query_test.rb +59 -0
  74. data/test/paynet_easy/paynet_easy_api/query/prototype/payment_query_test_prototype.rb +117 -0
  75. data/test/paynet_easy/paynet_easy_api/query/prototype/query_test_prototype.rb +190 -0
  76. data/test/paynet_easy/paynet_easy_api/query/prototype/sync_query_test_prototype.rb +88 -0
  77. data/test/paynet_easy/paynet_easy_api/query/query_factory_test.rb +21 -0
  78. data/test/paynet_easy/paynet_easy_api/query/return_query_test.rb +58 -0
  79. data/test/paynet_easy/paynet_easy_api/query/sale_form_query_test.rb +96 -0
  80. data/test/paynet_easy/paynet_easy_api/query/sale_query_test.rb +78 -0
  81. data/test/paynet_easy/paynet_easy_api/query/status_query_test.rb +81 -0
  82. data/test/paynet_easy/paynet_easy_api/query/transfer_by_ref_query_test.rb +63 -0
  83. data/test/paynet_easy/paynet_easy_api/transport/gateway_client_test.rb +22 -0
  84. data/test/paynet_easy/paynet_easy_api/transport/response_test.rb +26 -0
  85. data/test/paynet_easy/paynet_easy_api/util/property_accessor_test.rb +52 -0
  86. data/test/paynet_easy/paynet_easy_api/util/validator_test.rb +42 -0
  87. metadata +204 -0
@@ -0,0 +1,302 @@
1
+ require 'digest/sha1'
2
+ require 'payment_data/payment_transaction'
3
+ require 'util/property_accessor'
4
+ require 'util/validator'
5
+ require 'transport/request'
6
+ require 'transport/response'
7
+ require 'error/validation_error'
8
+
9
+ module PaynetEasy::PaynetEasyApi::Query::Prototype
10
+ class Query
11
+ include PaynetEasy::PaynetEasyApi::PaymentData
12
+ include PaynetEasy::PaynetEasyApi::Transport
13
+ include PaynetEasy::PaynetEasyApi::Util
14
+ include PaynetEasy::PaynetEasyApi::Error
15
+
16
+ # Request fields definition in format
17
+ # [
18
+ # [<first field name>:string, <first property path>:string, <is field required>:boolean, <validation rule>:string],
19
+ # [<second field name>:string, <second property path>:string, <is field required>:boolean, <validation rule>:string],
20
+ # ...
21
+ # [<last field name>:string, <last property path>:string, <is field required>:boolean, <validation rule>:string]
22
+ # ]
23
+ @request_fields_definition = []
24
+
25
+ # Request control code definition in format
26
+ # [<first part property path>:string, <second part property path>:string ... <last part property path>:string]
27
+ @signature_definition = []
28
+
29
+ # Response fields definition in format:
30
+ # [<first field_name>:string, <second field_name>:string ... <last field_name>:string]
31
+ @response_fields_definition = []
32
+
33
+ # Success response type
34
+ @success_response_type = ''
35
+
36
+ def initialize(api_method)
37
+ @api_method = api_method
38
+ end
39
+
40
+ # Create API gateway request from payment transaction data
41
+ #
42
+ # @param payment_transaction [PaymentTransaction] Payment transaction for query
43
+ #
44
+ # @return [Request] Request object
45
+ def create_request(payment_transaction)
46
+ validate_payment_transaction payment_transaction
47
+
48
+ request = payment_transaction_to_request payment_transaction
49
+
50
+ request.api_method = @api_method
51
+ request.end_point = payment_transaction.query_config.end_point
52
+ request.gateway_url = payment_transaction.query_config.gateway_url
53
+ request.signature = create_signature payment_transaction
54
+
55
+ request
56
+ rescue Exception => error
57
+ payment_transaction.add_error error
58
+ payment_transaction.status = PaymentTransaction::STATUS_ERROR
59
+
60
+ raise error
61
+ end
62
+
63
+ # Process API gateway response and update payment transaction
64
+ #
65
+ # @param payment_transaction [PaymentTransaction] Payment transaction for update
66
+ # @param response [Response] API gateway response
67
+ #
68
+ # @return [Response] API gateway response
69
+ def process_response(payment_transaction, response)
70
+ if response.processing? || response.approved?
71
+ validate = :validate_response_on_success
72
+ update = :update_payment_transaction_on_success
73
+ else
74
+ validate = :validate_response_on_error
75
+ update = :update_payment_transaction_on_error
76
+ end
77
+
78
+ begin
79
+ send validate, payment_transaction, response
80
+ rescue Exception => error
81
+ payment_transaction.add_error error
82
+ payment_transaction.status = PaymentTransaction::STATUS_ERROR
83
+
84
+ raise error
85
+ end
86
+
87
+ send update, payment_transaction, response
88
+
89
+ if response.error?
90
+ raise response.error
91
+ end
92
+
93
+ response
94
+ end
95
+
96
+ protected
97
+
98
+ # Validates payment transaction before request constructing
99
+ #
100
+ # @param payment_transaction [PaymentTransaction] Payment transaction for validation
101
+ def validate_payment_transaction(payment_transaction)
102
+ validate_query_config payment_transaction
103
+
104
+ error_message = ''
105
+ missed_fields = []
106
+ invalid_fields = []
107
+
108
+ request_fields_definition.each do |field_name, property_path, is_field_required, validation_rule|
109
+ field_value = PropertyAccessor.get_value payment_transaction, property_path, false
110
+
111
+ if field_value
112
+ begin
113
+ Validator.validate_by_rule field_value, validation_rule
114
+ rescue ValidationError => error
115
+ invalid_fields << "Field '#{field_name}' from property path '#{property_path}', #{error.message}."
116
+ end
117
+ elsif is_field_required
118
+ missed_fields << "Field '#{field_name}' from property path '#{property_path}' missed or empty."
119
+ end
120
+ end
121
+
122
+ unless missed_fields.empty?
123
+ error_message << "Some required fields missed or empty in PaymentTransaction: \n#{missed_fields.join "\n"}\n"
124
+ end
125
+
126
+ unless invalid_fields.empty?
127
+ error_message << "Some fields invalid in PaymentTransaction: \n#{invalid_fields.join "\n"}\n"
128
+ end
129
+
130
+ unless error_message.empty?
131
+ raise ValidationError, error_message
132
+ end
133
+ end
134
+
135
+ # Creates request from payment transaction
136
+ #
137
+ # @param payment_transaction [PaymentTransaction] Payment transaction for request constructing
138
+ #
139
+ # @return [Request] Request object
140
+ def payment_transaction_to_request(payment_transaction)
141
+ request_fields = {}
142
+
143
+ request_fields_definition.each do |field_name, property_path, _|
144
+ field_value = PropertyAccessor.get_value payment_transaction, property_path
145
+
146
+ if field_value
147
+ request_fields[field_name] = field_value
148
+ end
149
+ end
150
+
151
+ Request.new request_fields
152
+ end
153
+
154
+ # Generates the control code is used to ensure that it is a particular
155
+ # Merchant (and not a fraudster) that initiates the transaction.
156
+ #
157
+ # @param payment_transaction [PaymentTransaction] Payment transaction to generate control code
158
+ #
159
+ # @return [String] Generated control code
160
+ def create_signature(payment_transaction)
161
+ control_code = ''
162
+
163
+ signature_definition.each do |property_path|
164
+ control_code << PropertyAccessor.get_value(payment_transaction, property_path).to_s
165
+ end
166
+
167
+ Digest::SHA1.hexdigest control_code
168
+ end
169
+
170
+ # Validates response before payment transaction updating
171
+ # if payment transaction is processing or approved
172
+ #
173
+ # @param payment_transaction [PaymentTransaction] Payment transaction
174
+ # @param response [Response] Response for validating
175
+ def validate_response_on_success(payment_transaction, response)
176
+ if response.type != success_response_type
177
+ raise ValidationError, "Response type '#{response.type}' does " +
178
+ "not match success response type '#{success_response_type}'"
179
+ end
180
+
181
+ missed_fields = []
182
+
183
+ response_fields_definition.each do |field_name|
184
+ missed_fields << field_name unless response.key? field_name
185
+ end
186
+
187
+ unless missed_fields.empty?
188
+ raise ValidationError, "Some required fields missed or empty in Response: #{missed_fields.join ', '}"
189
+ end
190
+
191
+ validate_client_id payment_transaction, response
192
+ end
193
+
194
+ # Validates response before payment transaction updating
195
+ # if payment transaction is not processing or approved
196
+ #
197
+ # @param payment_transaction [PaymentTransaction] Payment transaction
198
+ # @param response [Response] Response for validating
199
+ def validate_response_on_error(payment_transaction, response)
200
+ unless [success_response_type, 'error', 'validation-error'].include? response.type
201
+ raise ValidationError, "Unknown response type '#{response.type}'"
202
+ end
203
+
204
+ validate_client_id payment_transaction, response
205
+ end
206
+
207
+ # Updates payment transaction by query response data
208
+ # if payment transaction is processing or approved
209
+ #
210
+ # @param payment_transaction [PaymentTransaction] Payment transaction
211
+ # @param response [Response] Response for payment transaction updating
212
+ def update_payment_transaction_on_success(payment_transaction, response)
213
+ payment_transaction.status = response.status
214
+ set_paynet_id payment_transaction, response
215
+ end
216
+
217
+ # Updates payment transaction by query response data
218
+ # if payment transaction is not processing or approved
219
+ #
220
+ # @param payment_transaction [PaymentTransaction] Payment transaction
221
+ # @param response [Response] Response for payment transaction updating
222
+ def update_payment_transaction_on_error(payment_transaction, response)
223
+ if response.declined?
224
+ payment_transaction.status = response.status
225
+ else
226
+ payment_transaction.status = PaymentTransaction::STATUS_ERROR
227
+ end
228
+
229
+ payment_transaction.add_error response.error
230
+ set_paynet_id payment_transaction, response
231
+ end
232
+
233
+ # Validates payment transaction query config
234
+ #
235
+ # @param payment_transaction [PaymentTransaction] Payment transaction
236
+ def validate_query_config(payment_transaction)
237
+ unless payment_transaction.query_config.signing_key
238
+ raise ValidationError, "Property 'signingKey' does not defined in PaymentTransaction property 'queryConfig'"
239
+ end
240
+ end
241
+
242
+ # Validates query object definition
243
+ def validate_query_definition
244
+ raise RuntimeError, 'You must configure @request_fields_definition' if request_fields_definition.empty?
245
+ raise RuntimeError, 'You must configure @signature_definition' if signature_definition.empty?
246
+ raise RuntimeError, 'You must configure @response_fields_definition' if response_fields_definition.empty?
247
+ raise RuntimeError, 'You must configure @success_response_type' if success_response_type.nil?
248
+ end
249
+
250
+ # Check, is payment transaction client order id and query response client order id equal or not.
251
+ #
252
+ # @param payment_transaction [PaymentTransaction] Payment transaction for update
253
+ # @param response [Response] API gateway response
254
+ def validate_client_id(payment_transaction, response)
255
+ payment_id = payment_transaction.payment.client_id
256
+ response_id = response.payment_client_id
257
+
258
+ if response_id && payment_id.to_s != response_id.to_s # Different types with equal values must pass validation
259
+ raise ValidationError, "Response client_id '#{response_id}' does not match Payment client_id '#{payment_id}'"
260
+ end
261
+ end
262
+
263
+ # Set PaynetEasy payment id to payment transaction Payment
264
+ #
265
+ # @param payment_transaction [PaymentTransaction] Payment transaction for update
266
+ # @param response [Response] API gateway response
267
+ def set_paynet_id(payment_transaction, response)
268
+ if response.payment_paynet_id
269
+ payment_transaction.payment.paynet_id = response.payment_paynet_id
270
+ end
271
+ end
272
+
273
+ class << self
274
+ # Make instance variables available in child classes
275
+ def inherited(subclass)
276
+ instance_variables.each do |variable_name|
277
+ subclass.instance_variable_set variable_name, instance_variable_get(variable_name)
278
+ end
279
+ end
280
+ end
281
+
282
+ # @return [Array]
283
+ def request_fields_definition
284
+ self.class.instance_variable_get :@request_fields_definition
285
+ end
286
+
287
+ # @return [Array]
288
+ def signature_definition
289
+ self.class.instance_variable_get :@signature_definition
290
+ end
291
+
292
+ # @return [Array]
293
+ def response_fields_definition
294
+ self.class.instance_variable_get :@response_fields_definition
295
+ end
296
+
297
+ # @return [String]
298
+ def success_response_type
299
+ self.class.instance_variable_get :@success_response_type
300
+ end
301
+ end
302
+ end
@@ -0,0 +1,19 @@
1
+ require 'util/string'
2
+ require 'query/prototype/query'
3
+
4
+ module PaynetEasy::PaynetEasyApi::Query
5
+ class QueryFactory
6
+ # Create API query object by API query method
7
+ #
8
+ # @param api_query_name [String] API query method name
9
+ #
10
+ # @return [Prototype::Query] API query object
11
+ def query(api_query_name)
12
+ query_class = "#{api_query_name.camelize}Query"
13
+ query_file = "query/#{api_query_name.gsub('-', '_')}_query"
14
+
15
+ require query_file
16
+ PaynetEasy::PaynetEasyApi::Query.const_get(query_class).new(api_query_name)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,46 @@
1
+ require 'query/prototype/payment_query'
2
+ require 'payment_data/payment'
3
+ require 'util/validator'
4
+ require 'error/validation_error'
5
+
6
+ module PaynetEasy::PaynetEasyApi::Query
7
+ class ReturnQuery < Prototype::PaymentQuery
8
+ include PaynetEasy::PaynetEasyApi::PaymentData
9
+ include PaynetEasy::PaynetEasyApi::Util
10
+ include PaynetEasy::PaynetEasyApi::Error
11
+
12
+ @request_fields_definition =
13
+ [
14
+ # mandatory
15
+ ['client_orderid', 'payment.client_id', true, Validator::ID],
16
+ ['orderid', 'payment.paynet_id', true, Validator::ID],
17
+ ['amount', 'payment.amount', true, Validator::AMOUNT],
18
+ ['currency', 'payment.currency', true, Validator::CURRENCY],
19
+ ['comment', 'payment.comment', true, Validator::MEDIUM_STRING],
20
+ ['login', 'query_config.login', true, Validator::MEDIUM_STRING]
21
+ ]
22
+
23
+ @signature_definition =
24
+ [
25
+ 'query_config.login',
26
+ 'payment.client_id',
27
+ 'payment.paynet_id',
28
+ 'payment.amount_in_cents',
29
+ 'payment.currency',
30
+ 'query_config.signing_key'
31
+ ]
32
+
33
+ @payment_status = Payment::STATUS_RETURN
34
+
35
+ protected
36
+
37
+ # @param payment_transaction [PaymentTransaction] Payment transaction for validation
38
+ def validate_payment_transaction(payment_transaction)
39
+ unless payment_transaction.payment.paid?
40
+ raise ValidationError, 'Payment must be paid up to return funds'
41
+ end
42
+
43
+ super payment_transaction
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,10 @@
1
+ require 'query/prototype/payment_form_query'
2
+ require 'payment_data/payment'
3
+
4
+ module PaynetEasy::PaynetEasyApi::Query
5
+ class SaleFormQuery < Prototype::PaymentFormQuery
6
+ include PaynetEasy::PaynetEasyApi::PaymentData
7
+
8
+ @payment_status = Payment::STATUS_CAPTURE
9
+ end
10
+ end
@@ -0,0 +1,53 @@
1
+ require 'query/prototype/payment_query'
2
+ require 'payment_data/payment'
3
+ require 'util/validator'
4
+
5
+ module PaynetEasy::PaynetEasyApi::Query
6
+ class SaleQuery < Prototype::PaymentQuery
7
+ include PaynetEasy::PaynetEasyApi::PaymentData
8
+ include PaynetEasy::PaynetEasyApi::Util
9
+
10
+ @request_fields_definition =
11
+ [
12
+ # mandatory
13
+ ['client_orderid', 'payment.client_id', true, Validator::ID],
14
+ ['order_desc', 'payment.description', true, Validator::LONG_STRING],
15
+ ['amount', 'payment.amount', true, Validator::AMOUNT],
16
+ ['currency', 'payment.currency', true, Validator::CURRENCY],
17
+ ['address1', 'payment.billing_address.first_line', true, Validator::MEDIUM_STRING],
18
+ ['city', 'payment.billing_address.city', true, Validator::MEDIUM_STRING],
19
+ ['zip_code', 'payment.billing_address.zip_code', true, Validator::ZIP_CODE],
20
+ ['country', 'payment.billing_address.country', true, Validator::COUNTRY],
21
+ ['phone', 'payment.billing_address.phone', true, Validator::PHONE],
22
+ ['ipaddress', 'payment.customer.ip_address', true, Validator::IP],
23
+ ['email', 'payment.customer.email', true, Validator::EMAIL],
24
+ ['card_printed_name', 'payment.credit_card.card_printed_name', true, Validator::LONG_STRING],
25
+ ['credit_card_number', 'payment.credit_card.credit_card_number', true, Validator::CREDIT_CARD_NUMBER],
26
+ ['expire_month', 'payment.credit_card.expire_month', true, Validator::MONTH],
27
+ ['expire_year', 'payment.credit_card.expire_year', true, Validator::YEAR],
28
+ ['cvv2', 'payment.credit_card.cvv2', true, Validator::CVV2],
29
+ ['redirect_url', 'query_config.redirect_url', true, Validator::URL],
30
+ # optional
31
+ ['first_name', 'payment.customer.first_name', false, Validator::MEDIUM_STRING],
32
+ ['last_name', 'payment.customer.last_name', false, Validator::MEDIUM_STRING],
33
+ ['ssn', 'payment.customer.ssn', false, Validator::SSN],
34
+ ['birthday', 'payment.customer.birthday', false, Validator::DATE],
35
+ ['state', 'payment.billing_address.state', false, Validator::COUNTRY],
36
+ ['cell_phone', 'payment.billing_address.cell_phone', false, Validator::PHONE],
37
+ ['destination', 'payment.destination', false, Validator::LONG_STRING],
38
+ ['site_url', 'query_config.site_url', false, Validator::URL],
39
+ ['server_callback_url', 'query_config.callback_url', false, Validator::URL]
40
+ ]
41
+
42
+ @signature_definition =
43
+ [
44
+ 'query_config.end_point',
45
+ 'payment.client_id',
46
+ 'payment.amount_in_cents',
47
+ 'payment.customer.email',
48
+ 'query_config.signing_key'
49
+ ]
50
+
51
+ @payment_status = Payment::STATUS_CAPTURE
52
+ end
53
+ end
@@ -0,0 +1,50 @@
1
+ require 'query/prototype/query'
2
+ require 'transport/response'
3
+
4
+ module PaynetEasy::PaynetEasyApi::Query
5
+ class StatusQuery < Prototype::Query
6
+ include PaynetEasy::PaynetEasyApi::Util
7
+ include PaynetEasy::PaynetEasyApi::Transport
8
+
9
+ @request_fields_definition =
10
+ [
11
+ # mandatory
12
+ ['client_orderid', 'payment.client_id', true, Validator::ID],
13
+ ['orderid', 'payment.paynet_id', true, Validator::ID],
14
+ ['login', 'query_config.login', true, Validator::MEDIUM_STRING]
15
+ ]
16
+
17
+ @signature_definition =
18
+ [
19
+ 'query_config.login',
20
+ 'payment.client_id',
21
+ 'payment.paynet_id',
22
+ 'query_config.signing_key'
23
+ ]
24
+
25
+ @response_fields_definition =
26
+ [
27
+ 'type',
28
+ 'status',
29
+ 'paynet-order-id',
30
+ 'merchant-order-id',
31
+ 'serial-number'
32
+ ]
33
+
34
+ @success_response_type = 'status-response'
35
+
36
+ protected
37
+
38
+ # @param payment_transaction [PaymentTransaction] Payment transaction
39
+ # @param response [Response] Response for payment transaction updating
40
+ def update_payment_transaction_on_success(payment_transaction, response)
41
+ super payment_transaction, response
42
+
43
+ if response.has_html?
44
+ response.needed_action = Response::NEEDED_SHOW_HTML
45
+ elsif response.processing?
46
+ response.needed_action = Response::NEEDED_STATUS_UPDATE
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,41 @@
1
+ require 'query/prototype/payment_query'
2
+ require 'payment_data/payment'
3
+ require 'util/validator'
4
+
5
+ module PaynetEasy::PaynetEasyApi::Query
6
+ class TransferByRefQuery < Prototype::PaymentQuery
7
+ include PaynetEasy::PaynetEasyApi::PaymentData
8
+ include PaynetEasy::PaynetEasyApi::Util
9
+
10
+ @request_fields_definition =
11
+ [
12
+ # mandatory
13
+ ['client_orderid', 'payment.client_id', true, Validator::ID],
14
+ ['amount', 'payment.amount', true, Validator::AMOUNT],
15
+ ['currency', 'payment.currency', true, Validator::CURRENCY],
16
+ ['ipaddress', 'payment.customer.ip_address', true, Validator::IP],
17
+ ['destination-card-ref-id', 'payment.recurrent_card_to.paynet_id', true, Validator::ID],
18
+ ['login', 'query_config.login', true,
19
+ Validator::MEDIUM_STRING],
20
+ # optional
21
+ ['order_desc', 'payment.description', false, Validator::LONG_STRING],
22
+ ['source-card-ref-id', 'payment.recurrent_card_from.paynet_id', false, Validator::ID],
23
+ ['cvv2', 'payment.recurrent_card_from.cvv2', false, Validator::CVV2],
24
+ ['redirect_url', 'query_config.redirect_url', false, Validator::URL],
25
+ ['server_callback_url', 'query_config.callback_url', false, Validator::URL]
26
+ ]
27
+
28
+ @signature_definition =
29
+ [
30
+ 'query_config.login',
31
+ 'payment.client_id',
32
+ 'payment.recurrent_card_from.paynet_id',
33
+ 'payment.recurrent_card_to.paynet_id',
34
+ 'payment.amount_in_cents',
35
+ 'payment.currency',
36
+ 'query_config.signing_key'
37
+ ]
38
+
39
+ @payment_status = Payment::STATUS_CAPTURE
40
+ end
41
+ end
@@ -0,0 +1,10 @@
1
+ require 'query/prototype/payment_form_query'
2
+ require 'payment_data/payment'
3
+
4
+ module PaynetEasy::PaynetEasyApi::Query
5
+ class TransferFormQuery < Prototype::PaymentFormQuery
6
+ include PaynetEasy::PaynetEasyApi::PaymentData
7
+
8
+ @payment_status = Payment::STATUS_CAPTURE
9
+ end
10
+ end
@@ -0,0 +1,21 @@
1
+ require 'transport/response'
2
+
3
+ module PaynetEasy::PaynetEasyApi::Transport
4
+ class CallbackResponse < Response
5
+ def amount
6
+ fetch 'amount', nil
7
+ end
8
+
9
+ def comment
10
+ fetch 'comment', nil
11
+ end
12
+
13
+ def merchant_data
14
+ fetch 'merchant_data', nil
15
+ end
16
+
17
+ def type=(type)
18
+ store 'type', type
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,91 @@
1
+ require 'net/http'
2
+ require 'uri'
3
+ require 'cgi'
4
+
5
+ require 'transport/request'
6
+ require 'transport/response'
7
+ require 'util/validator'
8
+
9
+ require 'error/validation_error'
10
+ require 'error/request_error'
11
+
12
+ module PaynetEasy::PaynetEasyApi::Transport
13
+ class GatewayClient
14
+ include Net
15
+ include PaynetEasy::PaynetEasyApi::Util
16
+ include PaynetEasy::PaynetEasyApi::Error
17
+
18
+ # Make request to the PaynetEasy gateway
19
+ #
20
+ # @param request [Request] Request data
21
+ #
22
+ # @return [Response] Response data
23
+ def make_request(request)
24
+ validate_request request
25
+ response = send_request request
26
+ parse_response response
27
+ end
28
+
29
+ protected
30
+
31
+ # Executes request
32
+ #
33
+ # @param request [Request] Request to execute
34
+ #
35
+ # @return [HTTPResponse] PaynetEasy response as HTTPResponse
36
+ def send_request(request)
37
+ begin
38
+ uri = URI "#{request.gateway_url}/#{request.api_method}/#{request.end_point}"
39
+
40
+ response = HTTP.start uri.hostname, uri.port, :use_ssl => uri.scheme == 'https' do |http|
41
+ post = HTTP::Post.new uri.request_uri
42
+ post.set_form_data request.request_fields
43
+ http.request post
44
+ end
45
+ rescue Exception => e
46
+ raise RequestError, "Error occurred. #{e.message}"
47
+ end
48
+
49
+ unless HTTPOK === response
50
+ raise RequestError, "Error occurred. HTTP code: '#{response.code}'. Server message: '#{response.message}'"
51
+ end
52
+
53
+ response
54
+ end
55
+
56
+ # Parse PaynetEasy response from string to Response object
57
+ #
58
+ # @param response [HTTPResponse] PaynetEasy response as HTTPResponse
59
+ #
60
+ # @return [Response] PaynetEasy response as Response
61
+ def parse_response(response)
62
+ unless response.body
63
+ raise ResponseError, 'PaynetEasy response is empty'
64
+ end
65
+
66
+ # Change hash format from {'key' => ['value']} to {'key' => 'value'} in map block
67
+ response_fields = Hash[CGI.parse(response.body).map {|key, value| [key, value.first]}]
68
+
69
+ Response.new response_fields
70
+ end
71
+
72
+ # Validates Request
73
+ #
74
+ # @param request [Request] Request for validation
75
+ def validate_request(request)
76
+ validation_errors = []
77
+
78
+ validation_errors << 'Request api method is empty' unless request.api_method
79
+ validation_errors << 'Request end point is empty' unless request.end_point
80
+ validation_errors << 'Request data is empty' unless request.request_fields.any?
81
+
82
+ unless Validator.validate_by_rule request.gateway_url, Validator::URL, false
83
+ validation_errors << 'Gateway url does not valid in Request'
84
+ end
85
+
86
+ if validation_errors.any?
87
+ raise ValidationError, "Some Request fields are invalid:\n#{validation_errors.join(";\n")}"
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,20 @@
1
+ module PaynetEasy::PaynetEasyApi::Transport
2
+ class Request
3
+ attr_accessor :api_method
4
+ attr_accessor :end_point
5
+ attr_accessor :gateway_url
6
+ attr_reader :request_fields
7
+
8
+ def initialize(request_fields = {})
9
+ @request_fields = request_fields
10
+ end
11
+
12
+ def gateway_url=(gateway_url)
13
+ @gateway_url = gateway_url.chomp '/'
14
+ end
15
+
16
+ def signature=(signature)
17
+ request_fields['control'] = signature
18
+ end
19
+ end
20
+ end