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.
@@ -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__), '.', 'utils')
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.to_params,
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
- if e.http_code and e.http_body
51
- parsed_error = parse_json_response(e.http_body)
52
- if parsed_error['error']
53
- error = "HTTP error #{e.http_code}: #{parsed_error['error']}"
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
- error = "Unexpected response code (#{e.message} - #{e.http_code})"
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 ResponseError.new("Server response is not a valid JSON.")
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
@@ -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 charge
80
- validation_error = self.card_hash ? nil : error_in_transaction
81
- raise TransactionError.new(validation_error) if validation_error
82
- raise TransactionError.new("Transaction already charged!") if self.status != :local
83
-
84
- request = PagarMe::Request.new('/transactions', 'POST', self.live)
85
- request.parameters = {
86
- :amount => self.amount.to_s,
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 error_in_transaction
136
- if self.card_number.length < 16 || self.card_number.length > 20 || !is_valid_credit_card(self.card_number)
137
- "Número do cartão inválido."
138
- elsif self.card_holder_name.length == 0
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 generate_card_hash
163
- request = PagarMe::Request.new("/transactions/card_hash_key", 'GET', self.live)
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
@@ -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
+