pagarme 0.15 → 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.
- checksums.yaml +7 -0
- data/Gemfile.lock +50 -0
- data/Rakefile +16 -0
- data/lib/pagarme.rb +19 -23
- data/lib/pagarme/address.rb +4 -0
- data/lib/pagarme/customer.rb +4 -0
- data/lib/pagarme/errors.rb +20 -6
- data/lib/pagarme/model.rb +53 -0
- data/lib/pagarme/pagarme_object.rb +141 -0
- data/lib/pagarme/phone.rb +4 -0
- data/lib/pagarme/plan.rb +56 -0
- data/lib/pagarme/request.rb +15 -15
- data/lib/pagarme/subscription.rb +36 -0
- data/lib/pagarme/transaction.rb +16 -153
- data/lib/pagarme/transaction_common.rb +82 -0
- data/lib/pagarme/util.rb +75 -0
- data/pagarme.gemspec +7 -5
- data/pagarme.rb +0 -40
- data/test/pagarme/plan.rb +65 -0
- data/test/pagarme/subscription.rb +29 -0
- data/test/pagarme/transaction.rb +131 -0
- data/test/test_helper.rb +166 -0
- metadata +85 -28
- data/lib/pagarme/utils.rb +0 -5
data/lib/pagarme/request.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'uri'
|
2
2
|
require 'rest_client'
|
3
3
|
require 'multi_json'
|
4
|
-
require File.join(File.dirname(__FILE__), '.', '
|
4
|
+
require File.join(File.dirname(__FILE__), '.', 'util')
|
5
5
|
require File.join(File.dirname(__FILE__), '.', 'errors')
|
6
6
|
|
7
7
|
module PagarMe
|
@@ -16,16 +16,20 @@ module PagarMe
|
|
16
16
|
self.headers = {}
|
17
17
|
end
|
18
18
|
|
19
|
+
def self.encode(params)
|
20
|
+
Util.normalize_params(params).to_params
|
21
|
+
end
|
22
|
+
|
19
23
|
def run
|
20
24
|
unless PagarMe.api_key
|
21
25
|
raise PagarMeError.new("You need to configure a API key before performing requests.")
|
22
26
|
end
|
23
27
|
|
28
|
+
self.headers = self.live ? { 'X-Live' => '1' } : {}
|
29
|
+
|
24
30
|
parameters = self.parameters.merge({
|
25
|
-
:api_key => PagarMe.api_key
|
26
|
-
:live => (self.live ? "1" : "0")
|
31
|
+
:api_key => PagarMe.api_key
|
27
32
|
})
|
28
|
-
|
29
33
|
error = nil
|
30
34
|
|
31
35
|
begin
|
@@ -34,7 +38,7 @@ module PagarMe
|
|
34
38
|
:url => PagarMe.full_api_url(self.path),
|
35
39
|
:headers => self.headers,
|
36
40
|
:open_timeout => 30,
|
37
|
-
:payload => parameters
|
41
|
+
:payload => self.class.encode(parameters),
|
38
42
|
:timeout => 90,
|
39
43
|
:verify_ssl => false # TODO: change to verify SSL
|
40
44
|
})
|
@@ -47,17 +51,13 @@ module PagarMe
|
|
47
51
|
raise
|
48
52
|
end
|
49
53
|
rescue RestClient::ExceptionWithResponse => e
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
else
|
55
|
-
error = "Invalid response code (#{e.http_code})."
|
56
|
-
end
|
54
|
+
parsed_error = parse_json_response(e.http_body)
|
55
|
+
if parsed_error['errors']
|
56
|
+
error = parsed_error
|
57
|
+
raise PagarMeError.initFromServerResponse(error)
|
57
58
|
else
|
58
|
-
|
59
|
+
raise PagarMeError.new(e.http_body)
|
59
60
|
end
|
60
|
-
raise ResponseError.new(error)
|
61
61
|
rescue RestClient::Exception, Errno::ECONNREFUSED => e
|
62
62
|
error = "Error connecting to server: connection refused"
|
63
63
|
end
|
@@ -73,7 +73,7 @@ module PagarMe
|
|
73
73
|
begin
|
74
74
|
MultiJson.load(response)
|
75
75
|
rescue MultiJson::LoadError => e
|
76
|
-
raise
|
76
|
+
raise PagarMeError.new("Server response is not a valid JSON.")
|
77
77
|
end
|
78
78
|
end
|
79
79
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.join(File.dirname(__FILE__), '..', 'pagarme')
|
3
|
+
|
4
|
+
module PagarMe
|
5
|
+
class Subscription < TransactionCommon
|
6
|
+
|
7
|
+
def to_hash
|
8
|
+
{
|
9
|
+
:amount => self.amount,
|
10
|
+
:payment_method => self.payment_method,
|
11
|
+
:installments => self.installments,
|
12
|
+
:card_hash => (self.payment_method == 'credit_card' ? self.card_hash : nil),
|
13
|
+
:postback_url => self.postback_url,
|
14
|
+
:customer_email => self.customer_email,
|
15
|
+
:customer => (self.customer) ? self.customer.to_hash : nil,
|
16
|
+
:plan_id => (self.plan) ? self.plan.id : nil
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def create
|
21
|
+
validation_error = self.card_hash ? nil : validate
|
22
|
+
self.card_hash = generate_card_hash unless self.card_hash
|
23
|
+
super
|
24
|
+
end
|
25
|
+
|
26
|
+
def charge(amount)
|
27
|
+
request = PagarMe::Request.new(self.url, 'POST')
|
28
|
+
request.parameters = {
|
29
|
+
:amount => amount,
|
30
|
+
}
|
31
|
+
response = request.run
|
32
|
+
update(response)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
data/lib/pagarme/transaction.rb
CHANGED
@@ -2,169 +2,32 @@
|
|
2
2
|
require 'openssl'
|
3
3
|
require 'base64'
|
4
4
|
require File.join(File.dirname(__FILE__), '..', 'pagarme')
|
5
|
-
require File.join(File.dirname(__FILE__), '.', 'utils')
|
6
|
-
require File.join(File.dirname(__FILE__), '.', 'errors')
|
7
5
|
|
8
6
|
module PagarMe
|
9
|
-
class Transaction
|
10
|
-
attr_accessor :amount, :card_number, :card_holder_name, :card_expiracy_month, :card_expiracy_year, :card_cvv, :live, :card_hash, :installments, :card_last_digits
|
11
|
-
|
12
|
-
# initializers
|
13
|
-
|
14
|
-
def initialize(first_parameter = nil, server_response = nil)
|
15
|
-
@statuses_codes = { :local => 0, :approved => 1, :processing => 2, :refused => 3, :chargebacked => 4 }
|
16
|
-
@date_created = nil
|
17
|
-
@id = nil
|
18
|
-
self.status = :local
|
19
|
-
self.live = PagarMe.live
|
20
|
-
self.installments = 1
|
21
|
-
|
22
|
-
self.card_number = self.card_holder_name = self.card_expiracy_month = self.card_expiracy_year = self.card_cvv = ""
|
23
|
-
self.amount = 0
|
24
|
-
|
25
|
-
# First parameter can be a hash with transaction parameters
|
26
|
-
# or a encrypted card_hash that came from client.
|
27
|
-
if first_parameter.class == String
|
28
|
-
self.card_hash = first_parameter
|
29
|
-
elsif first_parameter.class == Hash
|
30
|
-
self.amount = first_parameter[:amount]
|
31
|
-
self.card_number = first_parameter[:card_number]
|
32
|
-
self.card_holder_name = first_parameter[:card_holder_name]
|
33
|
-
self.card_expiracy_month = first_parameter[:card_expiracy_month]
|
34
|
-
self.card_expiracy_year = first_parameter[:card_expiracy_year]
|
35
|
-
self.card_cvv = first_parameter[:card_cvv]
|
36
|
-
self.installments = first_parameter[:installments] if first_parameter[:installments]
|
37
|
-
self.live = first_parameter[:live]
|
38
|
-
self.live = PagarMe.live unless self.live
|
39
|
-
end
|
40
|
-
|
41
|
-
update_fields_from_response(server_response) if server_response
|
42
|
-
end
|
43
|
-
|
44
|
-
def self.find_by_id(id)
|
45
|
-
request = PagarMe::Request.new("/transactions/#{id}", 'GET')
|
46
|
-
response = request.run
|
47
|
-
PagarMe::Transaction.new(nil, response)
|
48
|
-
end
|
49
|
-
|
50
|
-
def self.all(page = 1, count = 10)
|
51
|
-
raise TransactionError.new("Invalid page count") if page < 1 or count < 1
|
52
|
-
|
53
|
-
request = PagarMe::Request.new('/transactions', 'GET')
|
54
|
-
request.parameters = {
|
55
|
-
:page => page,
|
56
|
-
:count => count
|
57
|
-
}
|
58
|
-
|
59
|
-
response = request.run
|
60
|
-
response.map { |transaction_response| PagarMe::Transaction.new(nil, transaction_response) }
|
61
|
-
end
|
62
|
-
|
63
|
-
# getters
|
64
|
-
|
65
|
-
def status
|
66
|
-
@statuses_codes.key(@status)
|
67
|
-
end
|
68
|
-
|
69
|
-
def date_created
|
70
|
-
@date_created
|
71
|
-
end
|
72
|
-
|
73
|
-
def id
|
74
|
-
@id
|
75
|
-
end
|
76
|
-
|
7
|
+
class Transaction < TransactionCommon
|
77
8
|
# server requests methods
|
78
9
|
|
79
|
-
def
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
:
|
87
|
-
:installments => self.installments.to_i,
|
88
|
-
:card_hash => (self.card_hash ? self.card_hash : generate_card_hash)
|
10
|
+
def to_hash
|
11
|
+
{
|
12
|
+
:amount => self.amount,
|
13
|
+
:payment_method => self.payment_method,
|
14
|
+
:installments => self.installments,
|
15
|
+
:card_hash => (self.payment_method == 'credit_card' ? self.card_hash : nil),
|
16
|
+
:postback_url => self[:postback_url],
|
17
|
+
:customer => (self.customer) ? self.customer.to_hash : nil
|
89
18
|
}
|
90
|
-
|
91
|
-
response = request.run
|
92
|
-
update_fields_from_response(response)
|
93
|
-
end
|
94
|
-
|
95
|
-
def chargeback
|
96
|
-
raise TransactionError.new("Transaction already chargebacked!") if self.status == :chargebacked
|
97
|
-
raise TransactionError.new("Transaction needs to be approved to be chargebacked") if self.status != :approved
|
98
|
-
|
99
|
-
request = PagarMe::Request.new("/transactions/#{self.id}", 'DELETE', self.live)
|
100
|
-
response = request.run
|
101
|
-
update_fields_from_response(response)
|
102
|
-
end
|
103
|
-
|
104
|
-
|
105
|
-
private
|
106
|
-
|
107
|
-
|
108
|
-
def status=(status)
|
109
|
-
@status = @statuses_codes[status]
|
110
|
-
end
|
111
|
-
|
112
|
-
def update_fields_from_response(response)
|
113
|
-
@status = @statuses_codes[response['status'].to_sym]
|
114
|
-
@date_created = response['date_created']
|
115
|
-
self.amount = response['amount']
|
116
|
-
self.live = response['live']
|
117
|
-
self.card_holder_name = response['costumer_name']
|
118
|
-
self.installments = (!response['installments'] ? 1 : response['installments'].to_i)
|
119
|
-
self.card_last_digits = response['card_last_digits']
|
120
|
-
@id = response['id']
|
121
|
-
end
|
122
|
-
|
123
|
-
def is_valid_credit_card(card)
|
124
|
-
s1 = s2 = 0
|
125
|
-
card.to_s.reverse.chars.each_slice(2) do |odd, even|
|
126
|
-
s1 += odd.to_i
|
127
|
-
|
128
|
-
double = even.to_i * 2
|
129
|
-
double -= 9 if double >= 10
|
130
|
-
s2 += double
|
131
|
-
end
|
132
|
-
(s1 + s2) % 10 == 0
|
133
19
|
end
|
134
20
|
|
135
|
-
def
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
"Nome do portador inválido."
|
140
|
-
elsif self.card_expiracy_month.to_i <= 0 || self.card_expiracy_month.to_i > 12
|
141
|
-
"Mês de expiração inválido."
|
142
|
-
elsif self.card_expiracy_year.to_i <= 0
|
143
|
-
"Ano de expiração inválido."
|
144
|
-
elsif self.card_cvv.length < 3 || self.card_cvv.length > 4
|
145
|
-
"Código de segurança inválido."
|
146
|
-
elsif self.amount.to_i <= 0
|
147
|
-
"Valor inválido."
|
148
|
-
else
|
149
|
-
nil
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
def card_data_parameters
|
154
|
-
{
|
155
|
-
:card_number => self.card_number,
|
156
|
-
:card_holder_name => self.card_holder_name,
|
157
|
-
:card_expiracy_date => "#{self.card_expiracy_month}#{self.card_expiracy_year}",
|
158
|
-
:card_cvv => self.card_cvv
|
159
|
-
}
|
21
|
+
def charge
|
22
|
+
validation_error = self[:card_hash] ? nil : validate
|
23
|
+
self.card_hash = generate_card_hash unless self[:card_hash]
|
24
|
+
create
|
160
25
|
end
|
161
26
|
|
162
|
-
def
|
163
|
-
request = PagarMe::Request.new(
|
27
|
+
def refund
|
28
|
+
request = PagarMe::Request.new(self.url + '/refund', 'POST')
|
164
29
|
response = request.run
|
165
|
-
|
166
|
-
public_key = OpenSSL::PKey::RSA.new(response['public_key'])
|
167
|
-
"#{response['id']}_#{Base64.strict_encode64(public_key.public_encrypt(card_data_parameters.to_params))}"
|
30
|
+
update(response)
|
168
31
|
end
|
169
32
|
end
|
170
33
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.join(File.dirname(__FILE__), '..', 'pagarme')
|
3
|
+
|
4
|
+
module PagarMe
|
5
|
+
class TransactionCommon < Model
|
6
|
+
|
7
|
+
def initialize(response = {})
|
8
|
+
super(response)
|
9
|
+
self.payment_method = 'credit_card' unless self.payment_method
|
10
|
+
self.installments = 1 unless self.installments
|
11
|
+
self.status = 'local' unless self.status
|
12
|
+
before_set_filter :amount, :format_amount
|
13
|
+
end
|
14
|
+
|
15
|
+
def is_valid_credit_card(card)
|
16
|
+
s1 = s2 = 0
|
17
|
+
card.to_s.reverse.chars.each_slice(2) do |odd, even|
|
18
|
+
s1 += odd.to_i
|
19
|
+
|
20
|
+
double = even.to_i * 2
|
21
|
+
double -= 9 if double >= 10
|
22
|
+
s2 += double
|
23
|
+
end
|
24
|
+
(s1 + s2) % 10 == 0
|
25
|
+
end
|
26
|
+
|
27
|
+
def validate
|
28
|
+
error = PagarMeError.new
|
29
|
+
if self.payment_method == 'credit_card'
|
30
|
+
if !self.card_number || self.card_number.to_s.length < 16 || self.card_number.to_s.length > 20 || !is_valid_credit_card(self.card_number.to_s)
|
31
|
+
error.errors << PagarMeError.new("Número do cartão inválido.", 'card_number')
|
32
|
+
end
|
33
|
+
if !self.card_holder_name || !self.card_holder_name || self.card_holder_name.length == 0
|
34
|
+
error.errors << PagarMeError.new("Nome do portador inválido.", 'card_holder_name')
|
35
|
+
end
|
36
|
+
if !self.card_expiration_month || self.card_expiration_month.to_i <= 0 || self.card_expiration_month.to_i > 12
|
37
|
+
error.errors << PagarMeError.new("Mês de expiração inválido.", 'card_expiration_date')
|
38
|
+
end
|
39
|
+
if !self.card_expiration_year || self.card_expiration_year.to_i <= 0
|
40
|
+
error.errors << PagarMeError.new("Ano de expiração inválido.", 'card_expiration_date')
|
41
|
+
end
|
42
|
+
if !self.card_cvv || self.card_cvv.to_s.length < 3 || self.card_cvv.to_s.length > 4
|
43
|
+
error.errors << PagarMeError.new("Código de segurança inválido.", 'card_cvv')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
if(error.errors.any?)
|
47
|
+
error.message = error.errors.map {|e| e.message}
|
48
|
+
error.message = error.message.join(',')
|
49
|
+
raise error
|
50
|
+
else
|
51
|
+
nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def format_amount(amount)
|
56
|
+
if amount.kind_of?(String)
|
57
|
+
value = amount.gsub(/\./, "")
|
58
|
+
value = value.strip
|
59
|
+
value = value.match(/\d+/)[0]
|
60
|
+
amount = value
|
61
|
+
end
|
62
|
+
amount
|
63
|
+
end
|
64
|
+
|
65
|
+
def card_data_parameters
|
66
|
+
{
|
67
|
+
:card_number => self.card_number,
|
68
|
+
:card_holder_name => self.card_holder_name,
|
69
|
+
:card_expiration_date => "#{self.card_expiration_month}#{self.card_expiration_year}",
|
70
|
+
:card_cvv => self.card_cvv
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
def generate_card_hash
|
75
|
+
request = PagarMe::Request.new("/transactions/card_hash_key", 'GET')
|
76
|
+
response = request.run
|
77
|
+
|
78
|
+
public_key = OpenSSL::PKey::RSA.new(response['public_key'])
|
79
|
+
ret = "#{response['id']}_#{Base64.strict_encode64(public_key.public_encrypt(card_data_parameters.to_params))}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/lib/pagarme/util.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
module PagarMe
|
2
|
+
class Util
|
3
|
+
def self.pagarme_classes
|
4
|
+
return {
|
5
|
+
'transaction' => Transaction,
|
6
|
+
'plan' => Plan,
|
7
|
+
'customer' => Customer,
|
8
|
+
'subscription' => Subscription,
|
9
|
+
'address' => Address,
|
10
|
+
'phone' => Phone,
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.convert_to_pagarme_object(response)
|
15
|
+
case response
|
16
|
+
when Array
|
17
|
+
response.map{ |i| convert_to_pagarme_object(i)}
|
18
|
+
when Hash
|
19
|
+
self.pagarme_classes.fetch(response['object'], PagarMeObject).build(response)
|
20
|
+
else
|
21
|
+
response
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.url_encode(key)
|
26
|
+
URI.escape(key.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def self.normalize_params(parameters, parent = nil)
|
31
|
+
ret = []
|
32
|
+
parameters.each do |k, v|
|
33
|
+
current_key = parent ? "#{parent}[#{url_encode(k)}]" : url_encode(k)
|
34
|
+
case v
|
35
|
+
when Hash
|
36
|
+
ret += normalize_params(v, current_key)
|
37
|
+
when Array
|
38
|
+
ret += normalize_array_params(v, current_key)
|
39
|
+
else
|
40
|
+
ret << [current_key, v]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
ret
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.normalize_array_params(value, current_key)
|
47
|
+
ret = []
|
48
|
+
value.each do |element|
|
49
|
+
case element
|
50
|
+
when Hash
|
51
|
+
ret += normalize_params(element, current_key)
|
52
|
+
when Array
|
53
|
+
ret += normalize_array_params(element, current_key)
|
54
|
+
else
|
55
|
+
ret << ["#{current_key}[]", element]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
ret
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class Hash
|
64
|
+
def to_params
|
65
|
+
self.map{ |key, value| "#{key}=#{value}" }.join('&')
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class Array
|
70
|
+
def to_params
|
71
|
+
self.map{ |key, value| "#{key}=#{value}" }.join('&')
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
|