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.
- data/.gemtest +0 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +18 -0
- data/README.md +54 -0
- data/Rakefile +8 -0
- data/doc/00-basic-tutorial.md +254 -0
- data/doc/01-library-internals.md +6 -0
- data/doc/02-payment-scenarios.md +9 -0
- data/doc/library-internals/00-payment-data.md +162 -0
- data/doc/library-internals/01-payment-processor.md +163 -0
- data/doc/library-internals/02-validator.md +55 -0
- data/doc/library-internals/03-property-accessor.md +76 -0
- data/doc/payment-scenarios/00-sale-transactions.md +90 -0
- data/doc/payment-scenarios/01-preauth-capture-transactions.md +105 -0
- data/doc/payment-scenarios/02-transfer-transactions.md +89 -0
- data/doc/payment-scenarios/03-return-transactions.md +52 -0
- data/doc/payment-scenarios/04-recurrent-transactions.md +110 -0
- data/doc/payment-scenarios/05-payment-form-integration.md +59 -0
- data/doc/payment-scenarios/06-merchant-callbacks.md +29 -0
- data/example/capture.rb +12 -0
- data/example/common/functions.rb +56 -0
- data/lib/paynet_easy/paynet_easy_api/callback/callback_factory.rb +47 -0
- data/lib/paynet_easy/paynet_easy_api/callback/callback_prototype.rb +186 -0
- data/lib/paynet_easy/paynet_easy_api/callback/customer_return_callback.rb +28 -0
- data/lib/paynet_easy/paynet_easy_api/callback/paynet_easy_callback.rb +44 -0
- data/lib/paynet_easy/paynet_easy_api/error/paynet_error.rb +4 -0
- data/lib/paynet_easy/paynet_easy_api/error/request_error.rb +6 -0
- data/lib/paynet_easy/paynet_easy_api/error/response_error.rb +6 -0
- data/lib/paynet_easy/paynet_easy_api/error/validation_error.rb +6 -0
- data/lib/paynet_easy/paynet_easy_api/payment_data/billing_address.rb +41 -0
- data/lib/paynet_easy/paynet_easy_api/payment_data/credit_card.rb +32 -0
- data/lib/paynet_easy/paynet_easy_api/payment_data/customer.rb +35 -0
- data/lib/paynet_easy/paynet_easy_api/payment_data/data.rb +13 -0
- data/lib/paynet_easy/paynet_easy_api/payment_data/payment.rb +190 -0
- data/lib/paynet_easy/paynet_easy_api/payment_data/payment_transaction.rb +188 -0
- data/lib/paynet_easy/paynet_easy_api/payment_data/query_config.rb +95 -0
- data/lib/paynet_easy/paynet_easy_api/payment_data/recurrent_card.rb +40 -0
- data/lib/paynet_easy/paynet_easy_api/payment_processor.rb +251 -0
- data/lib/paynet_easy/paynet_easy_api/paynet_easy_api.rb +26 -0
- data/lib/paynet_easy/paynet_easy_api/query/capture_query.rb +30 -0
- data/lib/paynet_easy/paynet_easy_api/query/create_card_ref_query.rb +78 -0
- data/lib/paynet_easy/paynet_easy_api/query/get_card_info_query.rb +49 -0
- data/lib/paynet_easy/paynet_easy_api/query/make_rebill_query.rb +37 -0
- data/lib/paynet_easy/paynet_easy_api/query/preauth_form_query.rb +10 -0
- data/lib/paynet_easy/paynet_easy_api/query/preauth_query.rb +10 -0
- data/lib/paynet_easy/paynet_easy_api/query/prototype/payment_form_query.rb +69 -0
- data/lib/paynet_easy/paynet_easy_api/query/prototype/payment_query.rb +71 -0
- data/lib/paynet_easy/paynet_easy_api/query/prototype/query.rb +302 -0
- data/lib/paynet_easy/paynet_easy_api/query/query_factory.rb +19 -0
- data/lib/paynet_easy/paynet_easy_api/query/return_query.rb +46 -0
- data/lib/paynet_easy/paynet_easy_api/query/sale_form_query.rb +10 -0
- data/lib/paynet_easy/paynet_easy_api/query/sale_query.rb +53 -0
- data/lib/paynet_easy/paynet_easy_api/query/status_query.rb +50 -0
- data/lib/paynet_easy/paynet_easy_api/query/transfer_by_ref_query.rb +41 -0
- data/lib/paynet_easy/paynet_easy_api/query/transfer_form_query.rb +10 -0
- data/lib/paynet_easy/paynet_easy_api/transport/callback_response.rb +21 -0
- data/lib/paynet_easy/paynet_easy_api/transport/gateway_client.rb +91 -0
- data/lib/paynet_easy/paynet_easy_api/transport/request.rb +20 -0
- data/lib/paynet_easy/paynet_easy_api/transport/response.rb +136 -0
- data/lib/paynet_easy/paynet_easy_api/util/property_accessor.rb +60 -0
- data/lib/paynet_easy/paynet_easy_api/util/string.rb +9 -0
- data/lib/paynet_easy/paynet_easy_api/util/validator.rb +110 -0
- data/payneteasy-payneteasyapi.gemspec +16 -0
- data/test/paynet_easy/paynet_easy_api/callback/callback_factory_test.rb +22 -0
- data/test/paynet_easy/paynet_easy_api/callback/callback_test_prototype.rb +168 -0
- data/test/paynet_easy/paynet_easy_api/callback/customer_return_callback_test.rb +95 -0
- data/test/paynet_easy/paynet_easy_api/callback/paynet_easy_callback_test.rb +101 -0
- data/test/paynet_easy/paynet_easy_api/fake.rb +71 -0
- data/test/paynet_easy/paynet_easy_api/payment_processor_test.rb +255 -0
- data/test/paynet_easy/paynet_easy_api/query/capture_query_test.rb +48 -0
- data/test/paynet_easy/paynet_easy_api/query/create_card_ref_query_test.rb +116 -0
- data/test/paynet_easy/paynet_easy_api/query/get_card_info_query_test.rb +116 -0
- data/test/paynet_easy/paynet_easy_api/query/make_rebill_query_test.rb +59 -0
- data/test/paynet_easy/paynet_easy_api/query/prototype/payment_query_test_prototype.rb +117 -0
- data/test/paynet_easy/paynet_easy_api/query/prototype/query_test_prototype.rb +190 -0
- data/test/paynet_easy/paynet_easy_api/query/prototype/sync_query_test_prototype.rb +88 -0
- data/test/paynet_easy/paynet_easy_api/query/query_factory_test.rb +21 -0
- data/test/paynet_easy/paynet_easy_api/query/return_query_test.rb +58 -0
- data/test/paynet_easy/paynet_easy_api/query/sale_form_query_test.rb +96 -0
- data/test/paynet_easy/paynet_easy_api/query/sale_query_test.rb +78 -0
- data/test/paynet_easy/paynet_easy_api/query/status_query_test.rb +81 -0
- data/test/paynet_easy/paynet_easy_api/query/transfer_by_ref_query_test.rb +63 -0
- data/test/paynet_easy/paynet_easy_api/transport/gateway_client_test.rb +22 -0
- data/test/paynet_easy/paynet_easy_api/transport/response_test.rb +26 -0
- data/test/paynet_easy/paynet_easy_api/util/property_accessor_test.rb +52 -0
- data/test/paynet_easy/paynet_easy_api/util/validator_test.rb +42 -0
- 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
|