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,136 @@
|
|
|
1
|
+
require 'error/paynet_error'
|
|
2
|
+
|
|
3
|
+
module PaynetEasy::PaynetEasyApi::Transport
|
|
4
|
+
class Response
|
|
5
|
+
include PaynetEasy::PaynetEasyApi::Error
|
|
6
|
+
|
|
7
|
+
# Need to update payment status
|
|
8
|
+
NEEDED_STATUS_UPDATE = 'status_update'
|
|
9
|
+
|
|
10
|
+
# Need to show html from response
|
|
11
|
+
NEEDED_SHOW_HTML = 'show_html'
|
|
12
|
+
|
|
13
|
+
# Need redirect to response url
|
|
14
|
+
NEEDED_REDIRECT = 'redirect'
|
|
15
|
+
|
|
16
|
+
@@allowed_needed_actions =
|
|
17
|
+
[
|
|
18
|
+
NEEDED_STATUS_UPDATE,
|
|
19
|
+
NEEDED_SHOW_HTML,
|
|
20
|
+
NEEDED_REDIRECT
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
attr_accessor :needed_action
|
|
24
|
+
|
|
25
|
+
def initialize(response = {})
|
|
26
|
+
@data = Hash[response.map {|key, value| [key, value.to_s.strip]}]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def needed_action=(needed_action)
|
|
30
|
+
unless @@allowed_needed_actions.include? needed_action
|
|
31
|
+
raise ArgumentError, "Unknown needed action: '#{needed_action}'"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
@needed_action = needed_action
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def status_update_needed?
|
|
38
|
+
needed_action == NEEDED_STATUS_UPDATE
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def show_html_needed?
|
|
42
|
+
needed_action == NEEDED_SHOW_HTML
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def redirect_needed?
|
|
46
|
+
needed_action == NEEDED_REDIRECT
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def html
|
|
50
|
+
fetch 'html', nil
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def has_html?
|
|
54
|
+
!html.nil?
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def type
|
|
58
|
+
fetch('type').downcase if key? 'type'
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def status
|
|
62
|
+
if !fetch('status', nil) && !%w(validation-error error).include?(type)
|
|
63
|
+
store 'status', 'processing'
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
fetch('status').downcase if key? 'status'
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def approved?
|
|
70
|
+
status == 'approved'
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def processing?
|
|
74
|
+
status == 'processing'
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def declined?
|
|
78
|
+
%w(filtered declined).include? status
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def payment_client_id
|
|
82
|
+
any_key %w(merchant-order-id client_orderid merchant_order)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def payment_paynet_id
|
|
86
|
+
any_key %w(orderid paynet-order-id)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def card_paynet_id
|
|
90
|
+
fetch 'card-ref-id', nil
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def redirect_url
|
|
94
|
+
fetch 'redirect-url', nil
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def has_redirect_url?
|
|
98
|
+
!redirect_url.nil?
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def control_code
|
|
102
|
+
any_key %w(control merchant_control)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def error_message
|
|
106
|
+
any_key %w(error_message error-message)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def error_code
|
|
110
|
+
any_key %w(error_code error-code)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def error?
|
|
114
|
+
%w(validation-error error).include?(type) || status == 'error'
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def error
|
|
118
|
+
if error? || declined?
|
|
119
|
+
PaynetError.new error_message
|
|
120
|
+
else
|
|
121
|
+
raise RuntimeError, 'Response has no error'
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def method_missing(name, *args, &block)
|
|
126
|
+
@data.send name, *args, &block
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
protected
|
|
130
|
+
|
|
131
|
+
def any_key(keys)
|
|
132
|
+
keys.each {|key| return fetch key if key? key}
|
|
133
|
+
nil # if all keys missed in data
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
module PaynetEasy::PaynetEasyApi::Util
|
|
2
|
+
module PropertyAccessor
|
|
3
|
+
# Get property value by property path.
|
|
4
|
+
#
|
|
5
|
+
# @param object [Object] Object with data
|
|
6
|
+
# @param property_path [String] Path to property
|
|
7
|
+
# @param fail_on_error [TrueClass|FalseClass] Throw exception if error occurred or not
|
|
8
|
+
#
|
|
9
|
+
# @return [Object|NilClass]
|
|
10
|
+
def self.get_value(object, property_path, fail_on_error = true)
|
|
11
|
+
if !property_path.include? '.'
|
|
12
|
+
if object.respond_to? property_path
|
|
13
|
+
return object.send property_path
|
|
14
|
+
elsif fail_on_error
|
|
15
|
+
raise RuntimeError, "Expected object with method '#{property_path}'"
|
|
16
|
+
else
|
|
17
|
+
return
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
first_property, path_rest = property_path.split '.', 2
|
|
22
|
+
first_object = object.send first_property
|
|
23
|
+
|
|
24
|
+
if first_object
|
|
25
|
+
return self.get_value first_object, path_rest, fail_on_error
|
|
26
|
+
elsif fail_on_error
|
|
27
|
+
raise RuntimeError, "Object expected for property path '#{first_property}'"
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Set property value by property path.
|
|
32
|
+
#
|
|
33
|
+
# @param object [Object] Object with data
|
|
34
|
+
# @param property_path [String] Path to property
|
|
35
|
+
# @param value [Object] Value to set
|
|
36
|
+
# @param fail_on_error [TrueClass|FalseClass] Throw exception if error occurred or not
|
|
37
|
+
#
|
|
38
|
+
# @return [Object|NilClass]
|
|
39
|
+
def self.set_value(object, property_path, value, fail_on_error = true)
|
|
40
|
+
if !property_path.include? '.'
|
|
41
|
+
if object.respond_to? "#{property_path}="
|
|
42
|
+
return object.send "#{property_path}=", value
|
|
43
|
+
elsif fail_on_error
|
|
44
|
+
raise RuntimeError, "Expected object with method '#{property_path}='"
|
|
45
|
+
else
|
|
46
|
+
return
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
first_property, path_rest = property_path.split '.', 2
|
|
51
|
+
first_object = object.send(first_property)
|
|
52
|
+
|
|
53
|
+
if first_object
|
|
54
|
+
return self.set_value first_object, path_rest, value, fail_on_error
|
|
55
|
+
elsif fail_on_error
|
|
56
|
+
raise RuntimeError, "Object expected for property path '#{first_property}'"
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
require 'uri'
|
|
2
|
+
require 'ipaddr'
|
|
3
|
+
require 'error/validation_error'
|
|
4
|
+
|
|
5
|
+
module PaynetEasy::PaynetEasyApi::Util
|
|
6
|
+
module Validator
|
|
7
|
+
include PaynetEasy::PaynetEasyApi::Error
|
|
8
|
+
|
|
9
|
+
# Validate value as email
|
|
10
|
+
EMAIL = 'email'
|
|
11
|
+
|
|
12
|
+
# Validate value as IP address
|
|
13
|
+
IP = 'ip'
|
|
14
|
+
|
|
15
|
+
# Validate value as URL
|
|
16
|
+
URL = 'url'
|
|
17
|
+
|
|
18
|
+
# Validate value as month
|
|
19
|
+
MONTH = 'month'
|
|
20
|
+
|
|
21
|
+
# Validate value as year
|
|
22
|
+
YEAR = 'year'
|
|
23
|
+
|
|
24
|
+
# Validate value as phone number
|
|
25
|
+
PHONE = 'phone'
|
|
26
|
+
|
|
27
|
+
# Validate value as payment amount
|
|
28
|
+
AMOUNT = 'amount'
|
|
29
|
+
|
|
30
|
+
# Validate value as currency
|
|
31
|
+
CURRENCY = 'currency'
|
|
32
|
+
|
|
33
|
+
# Validate value as card verification value
|
|
34
|
+
CVV2 = 'cvv2'
|
|
35
|
+
|
|
36
|
+
# Validate value as zip code
|
|
37
|
+
ZIP_CODE = 'zip_code'
|
|
38
|
+
|
|
39
|
+
# Validate value as two-letter country or state code
|
|
40
|
+
COUNTRY = 'country'
|
|
41
|
+
|
|
42
|
+
# Validate value as date in format MMDDYY
|
|
43
|
+
DATE = 'date'
|
|
44
|
+
|
|
45
|
+
# Validate value as last four digits of social security number
|
|
46
|
+
SSN = 'ssn'
|
|
47
|
+
|
|
48
|
+
# Validate value as credit card number
|
|
49
|
+
CREDIT_CARD_NUMBER = 'credit_card_number'
|
|
50
|
+
|
|
51
|
+
# Validate value as different IDs (client, paynet, card-ref)
|
|
52
|
+
ID = 'id'
|
|
53
|
+
|
|
54
|
+
# Validate value as medium string
|
|
55
|
+
MEDIUM_STRING = 'medium_string'
|
|
56
|
+
|
|
57
|
+
# Validate value as long string
|
|
58
|
+
LONG_STRING = 'long_string'
|
|
59
|
+
|
|
60
|
+
# Regular expressions for some validation rules
|
|
61
|
+
@@rule_regexps =
|
|
62
|
+
{
|
|
63
|
+
EMAIL => /@+/,
|
|
64
|
+
PHONE => /^[0-9\-\+\(\)\s]{6,15}$/i,
|
|
65
|
+
AMOUNT => /^[0-9\.]{1,11}$/i,
|
|
66
|
+
CURRENCY => /^[A-Z]{1,3}$/i,
|
|
67
|
+
CVV2 => /^[\S\s]{3,4}$/i,
|
|
68
|
+
ZIP_CODE => /^[\S\s]{1,10}$/i,
|
|
69
|
+
COUNTRY => /^[A-Z]{1,2}$/i,
|
|
70
|
+
YEAR => /^[0-9]{1,2}$/i,
|
|
71
|
+
DATE => /^[0-9]{6}$/i,
|
|
72
|
+
SSN => /^[0-9]{1,4}$/i,
|
|
73
|
+
CREDIT_CARD_NUMBER => /^[0-9]{1,20}$/i,
|
|
74
|
+
ID => /^[\S\s]{1,20}$/i,
|
|
75
|
+
MEDIUM_STRING => /^[\S\s]{1,50}$/i,
|
|
76
|
+
LONG_STRING => /^[\S\s]{1,128}$/i
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# Validates value by given rule.
|
|
80
|
+
# Rule can be one of Validator constants or regExp.
|
|
81
|
+
#
|
|
82
|
+
# @param value [Object] Value for validation
|
|
83
|
+
# @param rule [String|Regexp] Rule for validation
|
|
84
|
+
# @param fail_on_error [TrueClass|FalseClass] Throw exception on invalid value or not
|
|
85
|
+
#
|
|
86
|
+
# @return [TrueClass|FalseClass] Validation result
|
|
87
|
+
def self.validate_by_rule(value, rule, fail_on_error = true)
|
|
88
|
+
begin
|
|
89
|
+
valid = case rule
|
|
90
|
+
when URL then URI::ABS_URI === value
|
|
91
|
+
when IP then IPAddr.new value
|
|
92
|
+
when MONTH then (1..12).include? value.to_i
|
|
93
|
+
else
|
|
94
|
+
regexp = @@rule_regexps.key?(rule) ? @@rule_regexps[rule] : rule
|
|
95
|
+
regexp === value.to_s
|
|
96
|
+
end
|
|
97
|
+
rescue Exception
|
|
98
|
+
valid = false
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
if valid
|
|
102
|
+
true
|
|
103
|
+
elsif fail_on_error
|
|
104
|
+
raise ValidationError, "Value '#{value}' does not match rule '#{rule}'"
|
|
105
|
+
else
|
|
106
|
+
false
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
Gem::Specification.new do |s|
|
|
2
|
+
s.name = 'payneteasy-payneteasyapi'
|
|
3
|
+
s.version = '0.1.0'
|
|
4
|
+
s.summary = 'Ruby library for PaynetEasy payment API.'
|
|
5
|
+
s.author = 'Artem Ponomarenko'
|
|
6
|
+
s.email = 'imenem@inbox.ru'
|
|
7
|
+
s.require_paths = ['lib', 'lib/paynet_easy/paynet_easy_api']
|
|
8
|
+
|
|
9
|
+
s.files = Dir['lib/**/*.rb'] + %w(.gemtest Gemfile Gemfile.lock Rakefile payneteasy-payneteasyapi.gemspec)
|
|
10
|
+
s.test_files = Dir['test/**/*.rb']
|
|
11
|
+
s.extra_rdoc_files = Dir['example/**/*.rb'] + Dir['doc/**/*.md'] << 'README.md'
|
|
12
|
+
|
|
13
|
+
s.required_ruby_version = '>= 1.9.3'
|
|
14
|
+
s.add_development_dependency 'test-unit'
|
|
15
|
+
s.add_development_dependency 'rake'
|
|
16
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require 'paynet_easy_api'
|
|
3
|
+
require 'callback/callback_factory'
|
|
4
|
+
require 'callback/customer_return_callback'
|
|
5
|
+
require 'callback/paynet_easy_callback'
|
|
6
|
+
|
|
7
|
+
module PaynetEasy::PaynetEasyApi::Callback
|
|
8
|
+
class CallbackFactoryTest < Test::Unit::TestCase
|
|
9
|
+
def setup
|
|
10
|
+
@object = CallbackFactory.new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def test_callback
|
|
14
|
+
callback = @object.callback 'customer_return'
|
|
15
|
+
assert_instance_of CustomerReturnCallback, callback
|
|
16
|
+
|
|
17
|
+
callback = @object.callback 'sale'
|
|
18
|
+
assert_instance_of PaynetEasyCallback, callback
|
|
19
|
+
assert_equal 'sale', callback.instance_variable_get(:@callback_type)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require 'digest/sha1'
|
|
3
|
+
require 'paynet_easy_api'
|
|
4
|
+
require 'callback/callback_prototype'
|
|
5
|
+
require 'payment_data/payment_transaction'
|
|
6
|
+
require 'payment_data/payment'
|
|
7
|
+
require 'payment_data/query_config'
|
|
8
|
+
require 'transport/callback_response'
|
|
9
|
+
require 'error/validation_error'
|
|
10
|
+
require 'error/paynet_error'
|
|
11
|
+
|
|
12
|
+
module PaynetEasy::PaynetEasyApi::Callback
|
|
13
|
+
module CallbackTestPrototype
|
|
14
|
+
include PaynetEasy::PaynetEasyApi::PaymentData
|
|
15
|
+
include PaynetEasy::PaynetEasyApi::Transport
|
|
16
|
+
include PaynetEasy::PaynetEasyApi::Error
|
|
17
|
+
|
|
18
|
+
SIGNING_KEY = 'D5F82EC1-8575-4482-AD89-97X6X0X20X22'
|
|
19
|
+
CLIENT_ID = 'CLIENT-112233'
|
|
20
|
+
PAYNET_ID = 'PAYNET-112233'
|
|
21
|
+
|
|
22
|
+
def test_process_callback_approved
|
|
23
|
+
raise NotImplementedError
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def assert_process_callback_approved(callback)
|
|
27
|
+
payment_transaction = payment_transaction()
|
|
28
|
+
callback_response = CallbackResponse.new callback
|
|
29
|
+
sign_callback callback_response
|
|
30
|
+
|
|
31
|
+
callback_processor.process_callback payment_transaction, callback_response
|
|
32
|
+
|
|
33
|
+
assert_true payment_transaction.approved?
|
|
34
|
+
assert_true payment_transaction.finished?
|
|
35
|
+
assert_false payment_transaction.has_errors?
|
|
36
|
+
|
|
37
|
+
[payment_transaction, callback_response]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def test_process_callback_declined
|
|
41
|
+
raise NotImplementedError
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def assert_process_callback_declined(callback)
|
|
45
|
+
payment_transaction = payment_transaction()
|
|
46
|
+
callback_response = CallbackResponse.new callback
|
|
47
|
+
sign_callback callback_response
|
|
48
|
+
|
|
49
|
+
callback_processor.process_callback payment_transaction, callback_response
|
|
50
|
+
|
|
51
|
+
assert_true payment_transaction.declined?
|
|
52
|
+
assert_true payment_transaction.finished?
|
|
53
|
+
assert_true payment_transaction.has_errors?
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def test_process_callback_error
|
|
57
|
+
raise NotImplementedError
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def assert_process_callback_error(callback)
|
|
61
|
+
payment_transaction = payment_transaction()
|
|
62
|
+
callback_response = CallbackResponse.new callback
|
|
63
|
+
sign_callback callback_response
|
|
64
|
+
|
|
65
|
+
begin
|
|
66
|
+
callback_processor.process_callback payment_transaction, callback_response
|
|
67
|
+
rescue PaynetError => error
|
|
68
|
+
assert_true payment_transaction.error?
|
|
69
|
+
assert_true payment_transaction.finished?
|
|
70
|
+
assert_true payment_transaction.has_errors?
|
|
71
|
+
assert_equal callback_response.error_message, error.message
|
|
72
|
+
|
|
73
|
+
[payment_transaction, callback_response]
|
|
74
|
+
else
|
|
75
|
+
flunk 'Exception must be raised'
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def test_process_callback_with_empty_control
|
|
80
|
+
assert_raise ValidationError, "Actual control code '' does not equal expected" do
|
|
81
|
+
callback_processor.process_callback payment_transaction, Response.new
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def test_process_callback_with_empty_fields
|
|
86
|
+
callback_response = CallbackResponse.new(
|
|
87
|
+
[
|
|
88
|
+
'status' => 'approved',
|
|
89
|
+
'orderid' => '_',
|
|
90
|
+
'client_orderid' => '_'
|
|
91
|
+
])
|
|
92
|
+
|
|
93
|
+
sign_callback callback_response
|
|
94
|
+
|
|
95
|
+
assert_raise ValidationError, 'Some required fields missed or empty in CallbackResponse' do
|
|
96
|
+
callback_processor.process_callback payment_transaction, callback_response
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def test_process_callback_with_unequal_fields
|
|
101
|
+
callback_response = CallbackResponse.new(
|
|
102
|
+
[
|
|
103
|
+
'status' => 'approved',
|
|
104
|
+
'orderid' => 'unequal',
|
|
105
|
+
'merchant_order' => 'unequal',
|
|
106
|
+
'client_orderid' => 'unequal'
|
|
107
|
+
])
|
|
108
|
+
|
|
109
|
+
sign_callback callback_response
|
|
110
|
+
|
|
111
|
+
assert_raise ValidationError, 'Some fields from CallbackResponse unequal properties from Payment' do
|
|
112
|
+
callback_processor.process_callback payment_transaction, callback_response
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def test_process_callback_with_invalid_status
|
|
117
|
+
callback_response = CallbackResponse.new(
|
|
118
|
+
[
|
|
119
|
+
'status' => 'processing',
|
|
120
|
+
'amount' => 0.99,
|
|
121
|
+
'orderid' => PAYNET_ID,
|
|
122
|
+
'merchant_order' => CLIENT_ID,
|
|
123
|
+
'client_orderid' => CLIENT_ID,
|
|
124
|
+
])
|
|
125
|
+
|
|
126
|
+
sign_callback callback_response
|
|
127
|
+
|
|
128
|
+
assert_raise ValidationError, "Invalid callback status: 'processing'" do
|
|
129
|
+
callback_processor.process_callback payment_transaction, callback_response
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
protected
|
|
134
|
+
|
|
135
|
+
# @return [CallbackPrototype]
|
|
136
|
+
def callback_processor
|
|
137
|
+
raise NotImplementedError
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# @return [PaymentTransaction]
|
|
141
|
+
def payment_transaction
|
|
142
|
+
PaymentTransaction.new(
|
|
143
|
+
{
|
|
144
|
+
'payment' => Payment.new(
|
|
145
|
+
{
|
|
146
|
+
'client_id' => CLIENT_ID,
|
|
147
|
+
'paynet_id' => PAYNET_ID,
|
|
148
|
+
'amount' => 0.99,
|
|
149
|
+
'currency' => 'USD',
|
|
150
|
+
}),
|
|
151
|
+
'query_config' => QueryConfig.new(
|
|
152
|
+
{
|
|
153
|
+
'signing_key' => SIGNING_KEY
|
|
154
|
+
})
|
|
155
|
+
})
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# @param callback_response [CallbackResponse]
|
|
159
|
+
def sign_callback(callback_response)
|
|
160
|
+
callback_response['control'] = Digest::SHA1.hexdigest(
|
|
161
|
+
callback_response.status +
|
|
162
|
+
callback_response.payment_paynet_id.to_s +
|
|
163
|
+
callback_response.payment_client_id.to_s +
|
|
164
|
+
SIGNING_KEY
|
|
165
|
+
)
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
require_relative './callback_test_prototype'
|
|
2
|
+
require 'callback/customer_return_callback'
|
|
3
|
+
|
|
4
|
+
module PaynetEasy::PaynetEasyApi::Callback
|
|
5
|
+
class CustomerReturnCallbackTest < Test::Unit::TestCase
|
|
6
|
+
include CallbackTestPrototype
|
|
7
|
+
|
|
8
|
+
def test_process_callback_approved
|
|
9
|
+
[
|
|
10
|
+
{
|
|
11
|
+
'status' => 'approved',
|
|
12
|
+
'amount' => 0.99,
|
|
13
|
+
'orderid' => PAYNET_ID,
|
|
14
|
+
'merchant_order' => CLIENT_ID,
|
|
15
|
+
'client_orderid' => CLIENT_ID,
|
|
16
|
+
}
|
|
17
|
+
].each do |callback|
|
|
18
|
+
assert_process_callback_approved callback
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def test_process_callback_declined
|
|
23
|
+
[
|
|
24
|
+
{
|
|
25
|
+
'status' => 'declined',
|
|
26
|
+
'amount' => 0.99,
|
|
27
|
+
'orderid' => PAYNET_ID,
|
|
28
|
+
'merchant_order' => CLIENT_ID,
|
|
29
|
+
'client_orderid' => CLIENT_ID,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
'status' => 'filtered',
|
|
33
|
+
'amount' => 0.99,
|
|
34
|
+
'orderid' => PAYNET_ID,
|
|
35
|
+
'merchant_order' => CLIENT_ID,
|
|
36
|
+
'client_orderid' => CLIENT_ID,
|
|
37
|
+
}
|
|
38
|
+
].each do |callback|
|
|
39
|
+
assert_process_callback_declined callback
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def test_process_callback_error
|
|
44
|
+
[
|
|
45
|
+
{
|
|
46
|
+
'status' => 'error',
|
|
47
|
+
'amount' => 0.99,
|
|
48
|
+
'orderid' => PAYNET_ID,
|
|
49
|
+
'merchant_order' => CLIENT_ID,
|
|
50
|
+
'client_orderid' => CLIENT_ID,
|
|
51
|
+
'error_message' => 'test type error message',
|
|
52
|
+
'error_code' => 5
|
|
53
|
+
}
|
|
54
|
+
].each do |callback|
|
|
55
|
+
assert_process_callback_error callback
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def test_process_callback_with_not_processing_transaction
|
|
60
|
+
payment_transaction = payment_transaction()
|
|
61
|
+
payment_transaction.status = PaymentTransaction::STATUS_APPROVED
|
|
62
|
+
|
|
63
|
+
callback_response = CallbackResponse.new(
|
|
64
|
+
[
|
|
65
|
+
'status' => 'processing',
|
|
66
|
+
'amount' => 0.99,
|
|
67
|
+
'orderid' => PAYNET_ID,
|
|
68
|
+
'merchant_order' => CLIENT_ID,
|
|
69
|
+
'client_orderid' => CLIENT_ID,
|
|
70
|
+
])
|
|
71
|
+
|
|
72
|
+
sign_callback callback_response
|
|
73
|
+
|
|
74
|
+
assert_raise ValidationError, 'Only processing payment transaction can be processed' do
|
|
75
|
+
callback_processor.process_callback payment_transaction, callback_response
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
protected
|
|
80
|
+
|
|
81
|
+
alias :callback_test_prototype_payment_transaction :payment_transaction
|
|
82
|
+
|
|
83
|
+
# @return [PaymentTransaction]
|
|
84
|
+
def payment_transaction
|
|
85
|
+
payment_transaction = callback_test_prototype_payment_transaction
|
|
86
|
+
payment_transaction.status = PaymentTransaction::STATUS_PROCESSING
|
|
87
|
+
payment_transaction
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# @return [CustomerReturnCallback]
|
|
91
|
+
def callback_processor
|
|
92
|
+
CustomerReturnCallback.new 'customer_return'
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|