locomotiva-braspag 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +4 -0
  5. data/Guardfile +10 -0
  6. data/README.md +59 -0
  7. data/RELEASES.md +20 -0
  8. data/Rakefile +6 -0
  9. data/config/braspag.yml +17 -0
  10. data/lib/generators/braspag/install/install_generator.rb +15 -0
  11. data/lib/generators/braspag/install/templates/config/braspag.yml +17 -0
  12. data/lib/locomotiva-braspag.rb +45 -0
  13. data/lib/locomotiva-braspag/bill.rb +164 -0
  14. data/lib/locomotiva-braspag/connection.rb +50 -0
  15. data/lib/locomotiva-braspag/credit_card.rb +210 -0
  16. data/lib/locomotiva-braspag/crypto/jar_webservice.rb +91 -0
  17. data/lib/locomotiva-braspag/crypto/webservice.rb +100 -0
  18. data/lib/locomotiva-braspag/eft.rb +90 -0
  19. data/lib/locomotiva-braspag/errors.rb +40 -0
  20. data/lib/locomotiva-braspag/order.rb +42 -0
  21. data/lib/locomotiva-braspag/payment_method.rb +73 -0
  22. data/lib/locomotiva-braspag/poster.rb +36 -0
  23. data/lib/locomotiva-braspag/protected_credit_card.rb +160 -0
  24. data/lib/locomotiva-braspag/utils.rb +32 -0
  25. data/lib/locomotiva-braspag/version.rb +3 -0
  26. data/locomotiva-braspag.gemspec +33 -0
  27. data/spec/bill_spec.rb +427 -0
  28. data/spec/connection_spec.rb +188 -0
  29. data/spec/credit_card_spec.rb +517 -0
  30. data/spec/crypto/jar_webservice_spec.rb +187 -0
  31. data/spec/crypto/webservice_spec.rb +143 -0
  32. data/spec/eft_spec.rb +209 -0
  33. data/spec/order_spec.rb +118 -0
  34. data/spec/poster_spec.rb +53 -0
  35. data/spec/protected_credit_card_spec.rb +296 -0
  36. data/spec/spec_helper.rb +21 -0
  37. data/spec/utils_spec.rb +47 -0
  38. metadata +244 -0
@@ -0,0 +1,210 @@
1
+ module Braspag
2
+ class CreditCard < PaymentMethod
3
+
4
+ MAPPING = {
5
+ :merchant_id => "merchantId",
6
+ :order => 'order',
7
+ :order_id => "orderId",
8
+ :customer_name => "customerName",
9
+ :amount => "amount",
10
+ :payment_method => "paymentMethod",
11
+ :holder => "holder",
12
+ :card_number => "cardNumber",
13
+ :expiration => "expiration",
14
+ :security_code => "securityCode",
15
+ :number_payments => "numberPayments",
16
+ :type => "typePayment"
17
+ }
18
+
19
+ AUTHORIZE_URI = "/webservices/pagador/Pagador.asmx/Authorize"
20
+ CAPTURE_URI = "/webservices/pagador/Pagador.asmx/Capture"
21
+ PARTIAL_CAPTURE_URI = "/webservices/pagador/Pagador.asmx/CapturePartial"
22
+ CANCELLATION_URI = "/webservices/pagador/Pagador.asmx/VoidTransaction"
23
+ PRODUCTION_INFO_URI = "/webservices/pagador/pedido.asmx/GetDadosCartao"
24
+ HOMOLOGATION_INFO_URI = "/pagador/webservice/pedido.asmx/GetDadosCartao"
25
+
26
+ def self.authorize(params = {})
27
+ connection = Braspag::Connection.instance
28
+ params[:merchant_id] = connection.merchant_id
29
+
30
+ self.check_params(params)
31
+
32
+ data = {}
33
+ MAPPING.each do |k, v|
34
+ case k
35
+ when :payment_method
36
+ data[v] = Braspag::Connection.instance.homologation? ? PAYMENT_METHODS[:braspag] : PAYMENT_METHODS[params[:payment_method]]
37
+ when :amount
38
+ data[v] = Utils.convert_decimal_to_string(params[:amount])
39
+ else
40
+ data[v] = params[k] || ""
41
+ end
42
+ end
43
+
44
+ response = Braspag::Poster.new(self.authorize_url).do_post(:authorize, data)
45
+
46
+ Utils::convert_to_map(response.body, {
47
+ :amount => nil,
48
+ :number => "authorisationNumber",
49
+ :message => 'message',
50
+ :return_code => 'returnCode',
51
+ :status => 'status',
52
+ :transaction_id => "transactionId"
53
+ })
54
+ end
55
+
56
+ def self.capture(order_id)
57
+ connection = Braspag::Connection.instance
58
+ merchant_id = connection.merchant_id
59
+
60
+ raise InvalidOrderId unless self.valid_order_id?(order_id)
61
+
62
+ data = {
63
+ MAPPING[:order_id] => order_id,
64
+ MAPPING[:merchant_id] => merchant_id
65
+ }
66
+
67
+ response = Braspag::Poster.new(self.capture_url).do_post(:capture, data)
68
+
69
+ Utils::convert_to_map(response.body, {
70
+ :amount => nil,
71
+ :number => "authorisationNumber",
72
+ :message => 'message',
73
+ :return_code => 'returnCode',
74
+ :status => 'status',
75
+ :transaction_id => "transactionId"
76
+ })
77
+ end
78
+
79
+ def self.partial_capture(order_id, amount)
80
+ connection = Braspag::Connection.instance
81
+ merchant_id = connection.merchant_id
82
+
83
+ raise InvalidOrderId unless self.valid_order_id?(order_id)
84
+
85
+ data = {
86
+ MAPPING[:order_id] => order_id,
87
+ MAPPING[:merchant_id] => merchant_id,
88
+ "captureAmount" => Utils.convert_decimal_to_string(amount)
89
+ }
90
+
91
+ response = Braspag::Poster.new(self.partial_capture_url).do_post(:partial_capture, data)
92
+
93
+ Utils::convert_to_map(response.body, {
94
+ :amount => nil,
95
+ :number => "authorisationNumber",
96
+ :message => 'message',
97
+ :return_code => 'returnCode',
98
+ :status => 'status',
99
+ :transaction_id => "transactionId"
100
+ })
101
+ end
102
+
103
+ def self.void(order_id)
104
+ connection = Braspag::Connection.instance
105
+ merchant_id = connection.merchant_id
106
+
107
+ raise InvalidOrderId unless self.valid_order_id?(order_id)
108
+
109
+ data = {
110
+ MAPPING[:order] => order_id,
111
+ MAPPING[:merchant_id] => merchant_id
112
+ }
113
+
114
+ response = Braspag::Poster.new(self.cancellation_url).do_post(:void, data)
115
+
116
+ Utils::convert_to_map(response.body, {
117
+ :amount => nil,
118
+ :number => "authorisationNumber",
119
+ :message => 'message',
120
+ :return_code => 'returnCode',
121
+ :status => 'status',
122
+ :transaction_id => "transactionId"
123
+ })
124
+ end
125
+
126
+ def self.info(order_id)
127
+ connection = Braspag::Connection.instance
128
+
129
+ raise InvalidOrderId unless self.valid_order_id?(order_id)
130
+
131
+ data = {:loja => connection.merchant_id, :numeroPedido => order_id.to_s}
132
+ response = Braspag::Poster.new(self.info_url).do_post(:info_credit_card, data)
133
+
134
+ response = Utils::convert_to_map(response.body, {
135
+ :checking_number => "NumeroComprovante",
136
+ :certified => "Autenticada",
137
+ :autorization_number => "NumeroAutorizacao",
138
+ :card_number => "NumeroCartao",
139
+ :transaction_number => "NumeroTransacao"
140
+ })
141
+
142
+ raise UnknownError if response[:checking_number].nil?
143
+ response
144
+ end
145
+
146
+ def self.check_params(params)
147
+ super
148
+
149
+ [:customer_name, :holder, :card_number, :expiration, :security_code, :number_payments, :type].each do |param|
150
+ raise IncompleteParams if params[param].nil?
151
+ end
152
+
153
+ raise InvalidHolder if params[:holder].to_s.size < 1 || params[:holder].to_s.size > 100
154
+
155
+ matches = params[:expiration].to_s.match /^(\d{2})\/(\d{2,4})$/
156
+ raise InvalidExpirationDate unless matches
157
+ begin
158
+ year = matches[2].to_i
159
+ year = "20#{year}" if year.size == 2
160
+
161
+ Date.new(year.to_i, matches[1].to_i)
162
+ rescue ArgumentError
163
+ raise InvalidExpirationDate
164
+ end
165
+
166
+ raise InvalidSecurityCode if params[:security_code].to_s.size < 1 || params[:security_code].to_s.size > 4
167
+
168
+ raise InvalidNumberPayments if params[:number_payments].to_i < 1 || params[:number_payments].to_i > 99
169
+ end
170
+
171
+ # <b>DEPRECATED:</b> Please use <tt>ProtectedCreditCard.save</tt> instead.
172
+ def self.save(params)
173
+ warn "[DEPRECATION] `CreditCard.save` is deprecated. Please use `ProtectedCreditCard.save` instead."
174
+ ProtectedCreditCard.save(params)
175
+ end
176
+
177
+ # <b>DEPRECATED:</b> Please use <tt>ProtectedCreditCard.get</tt> instead.
178
+ def self.get(just_click_key)
179
+ warn "[DEPRECATION] `CreditCard.get` is deprecated. Please use `ProtectedCreditCard.get` instead."
180
+ ProtectedCreditCard.get(just_click_key)
181
+ end
182
+
183
+ # <b>DEPRECATED:</b> Please use <tt>ProtectedCreditCard.just_click_shop</tt> instead.
184
+ def self.just_click_shop(params = {})
185
+ warn "[DEPRECATION] `CreditCard.just_click_shop` is deprecated. Please use `ProtectedCreditCard.just_click_shop` instead."
186
+ ProtectedCreditCard.just_click_shop(params)
187
+ end
188
+
189
+ def self.info_url
190
+ connection = Braspag::Connection.instance
191
+ connection.braspag_url + (connection.production? ? PRODUCTION_INFO_URI : HOMOLOGATION_INFO_URI)
192
+ end
193
+
194
+ def self.authorize_url
195
+ Braspag::Connection.instance.braspag_url + AUTHORIZE_URI
196
+ end
197
+
198
+ def self.capture_url
199
+ Braspag::Connection.instance.braspag_url + CAPTURE_URI
200
+ end
201
+
202
+ def self.partial_capture_url
203
+ Braspag::Connection.instance.braspag_url + PARTIAL_CAPTURE_URI
204
+ end
205
+
206
+ def self.cancellation_url
207
+ Braspag::Connection.instance.braspag_url + CANCELLATION_URI
208
+ end
209
+ end
210
+ end
@@ -0,0 +1,91 @@
1
+ module Braspag
2
+ module Crypto
3
+ class JarWebservice
4
+ def self.encrypt(map)
5
+ crypto_key = Braspag::Connection.instance.crypto_key
6
+ raise Braspag::IncompleteParams if map.nil?
7
+ raise Braspag::IncompleteParams unless map.is_a?(Hash)
8
+
9
+ request = ::HTTPI::Request.new encrypt_uri
10
+
11
+ data = {:key => crypto_key, :fields => map}
12
+
13
+ request.headers["Content-Type"] = "application/json"
14
+
15
+ request.body = data.to_json
16
+
17
+ response = ::HTTPI.post request
18
+
19
+ begin
20
+ response = JSON.parse(response.body)
21
+ rescue Exception => e
22
+ raise UnknownError
23
+ end
24
+
25
+ raise IncompleteParams if (
26
+ response["msg"] == "INVALID FORMAT" ||
27
+ response["msg"] == "INVALID FIELDS"
28
+ )
29
+
30
+ raise InvalidEncryptedKey if response["msg"] == "INVALID ENCRYPTED STRING"
31
+ raise InvalidCryptKey if response["msg"] == "INVALID KEY"
32
+
33
+ response["encrypt"]
34
+ end
35
+
36
+ def self.decrypt(encrypted, fields)
37
+ crypto_key = Braspag::Connection.instance.crypto_key
38
+ raise Braspag::InvalidEncryptedKey if encrypted.nil?
39
+ raise Braspag::InvalidEncryptedKey unless encrypted.is_a?(String)
40
+
41
+ raise Braspag::IncompleteParams if fields.nil?
42
+ raise Braspag::IncompleteParams unless fields.is_a?(Array)
43
+
44
+
45
+ request = ::HTTPI::Request.new decrypt_uri
46
+ request.body = {
47
+ "key" => crypto_key,
48
+ "encrypted" => encrypted,
49
+ "fields" => fields
50
+ }.to_json
51
+
52
+ request.headers["Content-Type"] = "application/json"
53
+
54
+ response = ::HTTPI.post request
55
+
56
+ begin
57
+ response = JSON.parse(response.body)
58
+ rescue Exception => e
59
+ raise UnknownError
60
+ end
61
+
62
+ raise IncompleteParams if (
63
+ response["msg"] == "INVALID FORMAT" ||
64
+ response["msg"] == "INVALID FIELDS"
65
+ )
66
+
67
+ raise InvalidEncryptedKey if response["msg"] == "INVALID ENCRYPTED STRING"
68
+
69
+ raise InvalidCryptKey if response["msg"] == "INVALID KEY"
70
+
71
+ map = {}
72
+ response["fields"].each do |key,value|
73
+ map[key.downcase.to_sym] = value
74
+ end
75
+ map
76
+ end
77
+
78
+ protected
79
+ def self.encrypt_uri
80
+ connection_uri = Braspag::Connection.instance.crypto_url
81
+ "#{connection_uri}/v1/encrypt.json"
82
+ end
83
+
84
+ def self.decrypt_uri
85
+ connection_uri = Braspag::Connection.instance.crypto_url
86
+ "#{connection_uri}/v1/decrypt.json"
87
+ end
88
+
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,100 @@
1
+ module Braspag
2
+ module Crypto
3
+ class Webservice
4
+ def self.encrypt(map)
5
+ connection = Braspag::Connection.instance
6
+ raise Braspag::IncompleteParams if map.nil?
7
+ raise Braspag::IncompleteParams unless map.is_a?(Hash)
8
+
9
+ request = ::HTTPI::Request.new self.uri
10
+
11
+ fields = "\n"
12
+ map.each do |key, value|
13
+ fields.concat(" <tns:string>#{key}=#{value}</tns:string>\n")
14
+ end
15
+
16
+ request.body = <<-STRING
17
+ <?xml version="1.0" encoding="utf-8"?>
18
+ <env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
19
+ <env:Header />
20
+ <env:Body>
21
+ <tns:EncryptRequest xmlns:tns="https://www.pagador.com.br/webservice/BraspagGeneralService">
22
+ <tns:merchantId>#{connection.merchant_id}</tns:merchantId>
23
+ <tns:request>
24
+ #{fields}
25
+ </tns:request>
26
+ </tns:EncryptRequest>
27
+ </env:Body>
28
+ </env:Envelope>
29
+ STRING
30
+
31
+ request.headers["Content-Type"] = "text/xml"
32
+
33
+ response = ::HTTPI.post request
34
+
35
+ document = Nokogiri::XML(response.body)
36
+
37
+ raise Braspag::UnknownError if document.children.empty?
38
+
39
+ #melhorar este parser cof cof
40
+ response = document.children.children.children.children.children.to_s
41
+
42
+ raise Braspag::InvalidMerchantId if (response == 'Erro BP 011' || response == 'Erro BP 012')
43
+ raise Braspag::InvalidIP if (response == 'Erro BP 067' || response == 'Erro BP 068')
44
+
45
+ response
46
+ end
47
+
48
+ def self.decrypt(encripted_text)
49
+ connection = Braspag::Connection.instance
50
+
51
+ raise Braspag::IncompleteParams if encripted_text.nil?
52
+ raise Braspag::IncompleteParams unless encripted_text.is_a?(String)
53
+
54
+ request = ::HTTPI::Request.new self.uri
55
+
56
+ request.body = <<-STRING
57
+ <?xml version="1.0" encoding="utf-8"?>
58
+ <env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
59
+ <env:Header />
60
+ <env:Body>
61
+ <tns:DecryptRequest xmlns:tns="https://www.pagador.com.br/webservice/BraspagGeneralService">
62
+ <tns:merchantId>#{connection.merchant_id}</tns:merchantId>
63
+ <tns:cryptString>#{encripted_text}</tns:cryptString>
64
+ </tns:DecryptRequest>
65
+ </env:Body>
66
+ </env:Envelope>
67
+ STRING
68
+
69
+ request.headers["Content-Type"] = "text/xml"
70
+
71
+ response = ::HTTPI.post request
72
+
73
+ document = Nokogiri::XML(response.body)
74
+ raise Braspag::UnknownError if document.children.empty?
75
+
76
+ result_error = document.children.children.children.children.children.first.content.to_s
77
+
78
+ raise Braspag::InvalidMerchantId if (result_error == 'Erro BP 011' || result_error == 'Erro BP 012')
79
+ raise Braspag::InvalidIP if (result_error == 'Erro BP 067' || result_error == 'Erro BP 068')
80
+
81
+ self.convert_request_to_map document
82
+ end
83
+
84
+ protected
85
+ def self.uri
86
+ connection = Braspag::Connection.instance
87
+ "#{connection.braspag_url}/BraspagGeneralService/BraspagGeneralService.asmx"
88
+ end
89
+
90
+ def self.convert_request_to_map(document)
91
+ map = {}
92
+ document.children.children.children.children.children.each do |n|
93
+ values = n.content.to_s.split("=")
94
+ map[values[0].downcase.to_sym] = values[1]
95
+ end
96
+ map
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,90 @@
1
+ module Braspag
2
+ class Eft < PaymentMethod
3
+
4
+ PAYMENT_METHODS = {
5
+ :bradesco => 11,
6
+ :itau => 12,
7
+ :banco_do_brasil => 15,
8
+ :banco_real => 16,
9
+ :banrisul => 30,
10
+ :unibanco => 31
11
+ }
12
+
13
+ MAPPING = {
14
+ :merchant_id => "Id_Loja",
15
+ :order_id => "VENDAID",
16
+ :customer_name => "nome",
17
+ :customer_id => "CPF",
18
+ :amount => "VALOR",
19
+ :payment_method => "CODPAGAMENTO",
20
+ :installments => "PARCELAS",
21
+ :has_interest => "TIPOPARCELADO"
22
+ }
23
+
24
+ ACTION_URI = "/pagador/passthru.asp"
25
+
26
+ def self.generate(params, crypto_strategy = nil)
27
+ connection = Braspag::Connection.instance
28
+ params[:merchant_id] = connection.merchant_id
29
+
30
+ params = self.normalize_params(params)
31
+ self.check_params(params)
32
+
33
+ data = {}
34
+
35
+ MAPPING.each do |k, v|
36
+ case k
37
+ when :payment_method
38
+ data[v] = PAYMENT_METHODS[params[:payment_method]]
39
+ when :amount
40
+ data[v] = Utils.convert_decimal_to_string(params[:amount])
41
+ else
42
+ data[v] = params[k] || ""
43
+ end
44
+ end
45
+
46
+ html = "<form id=\"form_tef_#{params[:order_id]}\" name=\"form_tef_#{params[:order_id]}\" action=\"#{self.action_url}\" method=\"post\">"
47
+
48
+ if crypto_strategy.nil?
49
+ data.each do |key, value|
50
+ html << "<input type=\"text\" name=\"#{key}\" value=\"#{value}\" />"
51
+ end
52
+ else
53
+ data.delete("Id_Loja")
54
+ html << "<input type=\"text\" name=\"Id_Loja\" value=\"#{params[:merchant_id]}\" />"
55
+ html << "<input type=\"text\" name=\"crypt\" value=\"#{crypto_strategy.encrypt(data)}\" />"
56
+ end
57
+
58
+ html << "</form><script type=\"text/javascript\" charset=\"utf-8\">document.forms[\"form_tef_#{params[:order_id]}\"].submit();</script>"
59
+
60
+ html
61
+ end
62
+
63
+ def self.normalize_params(params)
64
+ params = super
65
+
66
+ params[:installments] = params[:installments].to_i unless params[:installments].nil?
67
+ params[:installments] ||= 1
68
+
69
+ params[:has_interest] = params[:has_interest] == true ? "1" : "0"
70
+
71
+ params
72
+ end
73
+
74
+ def self.check_params(params)
75
+ super
76
+
77
+ if params[:installments]
78
+ raise InvalidInstallments if params[:installments].to_i < 1 || params[:installments].to_i > 99
79
+ end
80
+
81
+ if params[:has_interest]
82
+ raise InvalidHasInterest if params[:has_interest] != "1" && params[:has_interest] != "0"
83
+ end
84
+ end
85
+
86
+ def self.action_url
87
+ Braspag::Connection.instance.braspag_url + ACTION_URI
88
+ end
89
+ end
90
+ end