tray-checkout 0.0.0 → 0.0.1

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/CHANGELOG.rdoc CHANGED
@@ -1,2 +1,5 @@
1
+ == Version 0.0.1
2
+ - First stable version.
3
+
1
4
  == Version 0.0.0
2
5
  - First version, unstable yet.
data/README.rdoc CHANGED
@@ -7,6 +7,7 @@ Tray Checkout API
7
7
  === Gemfile
8
8
  gem 'tray-checkout'
9
9
 
10
+
10
11
  === Direct installation
11
12
  $ gem install tray-checkout
12
13
 
@@ -15,7 +16,91 @@ Tray Checkout API
15
16
 
16
17
  require 'tray-checkout'
17
18
 
18
- t = Tray::Checkout::Transaction.new
19
+ transaction = Tray::Checkout::Transaction.new
20
+
21
+ Getting an existing transaction:
22
+ txn = transaction.get("522045453u5uu32e0u8014f060uuu5uu")
23
+ txn[:success] # => true
24
+ txn[:transaction_token] # => "522045453u5uu32e0u8014f060uuu5uu"
25
+ txn[:transaction_id] # => 501
26
+ txn[:status] # => :waiting_payment
27
+ txn[:payment_method] # => :boleto
28
+ txn[:price_payment] # => 213.21
29
+ txn[:price_seller] # => 199.19
30
+ txn[:split] # => 1
31
+ txn[:payment][:url_payment] # => "http://checkout.sandbox.tray.com.br/payment/billet/u9uuu8731319u59u3073u9011uu6u6uu"
32
+ txn[:date_transaction].strftime("%d/%m/%Y") # => "03/12/2012"
33
+
34
+ When the transaction is not found:
35
+ txn = transaction.get("xxxxx00000yyyy")
36
+ txn[:success] # => false
37
+ txn[:transaction_id] # => nil
38
+ txn[:errors].first[:code] # => "003042"
39
+ txn[:errors].first[:message] # => "Transação não encontrada"
40
+
41
+ Creating a successful transaction:
42
+ txn = transaction.create(
43
+ token_account: "949u5uu9ef36f7u",
44
+ customer: {
45
+ name: "Pedro Bonamides",
46
+ cpf: "18565842673",
47
+ email: "pedro@bo.com.br",
48
+ sex: :male,
49
+ marital_status: :single,
50
+ contacts: [
51
+ { contact_type: :home,
52
+ number_contact: "1142360873"
53
+ }
54
+ ],
55
+ addresses: [
56
+ { address_type: :billing,
57
+ street: "Avenida Pedro Alvares Cabral",
58
+ number: "123",
59
+ neighborhood: "Parque Ibirapuera",
60
+ postal_code: "04094050",
61
+ city: "São Paulo",
62
+ state: "SP"
63
+ }
64
+ ]
65
+ },
66
+ transaction: {
67
+ order_number: "R1245",
68
+ shipping_type: "Sedex",
69
+ shipping_price: 13.94,
70
+ url_notification: "http://prodis.blog.br/tray_notification"
71
+ },
72
+ transaction_product: [
73
+ { code: "LOGO-8278",
74
+ quantity: 2,
75
+ price_unit: 100.99,
76
+ description: "Logo Prodis"
77
+ },
78
+ { code: "877",
79
+ quantity: 1,
80
+ price_unit: 10.00,
81
+ description: "Outro produto"
82
+ }
83
+ ],
84
+ payment: {
85
+ payment_method: :mastercard,
86
+ split: 3,
87
+ card_name: "ZEFINHA NOCEGA",
88
+ card_number: "5105105105105100",
89
+ card_expdate_month: "09",
90
+ card_expdate_year: "2015",
91
+ card_cvv: "123"
92
+ }
93
+ )
94
+ txn[:success] # => true
95
+ txn[:transaction_token] # => "87654321u5uu92e4u09876543uuu5uu"
96
+ txn[:transaction_id] # => 503
97
+ txn[:status] # => :approved
98
+ txn[:status_name] # => "Aprovada"
99
+ txn[:payment_method] # => :mastercard
100
+ txn[:payment_method_name] # => "Mastercard"
101
+ txn[:price_payment] # => 213.21
102
+ txn[:price_seller] # => 199.19
103
+ txn[:date_payment].strftime("%d/%m/%Y") # => "05/12/2012"
19
104
 
20
105
 
21
106
  == Author
@@ -0,0 +1,53 @@
1
+ # encoding: UTF-8
2
+
3
+ module Tray
4
+ module Checkout
5
+ PAYMENT_METHOD = {
6
+ diners: 2,
7
+ visa: 3,
8
+ mastercard: 4,
9
+ american_express: 5,
10
+ boleto: 6,
11
+ itau_shopline: 7,
12
+ pagamento_com_saldo: 8,
13
+ peela: 14,
14
+ discover: 15,
15
+ elo: 16
16
+ }
17
+
18
+ TRANSACTION_STATUS = {
19
+ waiting_payment: 4,
20
+ processing: 5,
21
+ approved: 6,
22
+ canceled: 7,
23
+ disputing: 24,
24
+ monitoring: 87,
25
+ recovering: 88,
26
+ disapproved: 89
27
+ }
28
+
29
+ CONTACT_TYPE = {
30
+ home: "H",
31
+ mobile: "M",
32
+ work: "W"
33
+ }
34
+
35
+ ADDRESS_TYPE = {
36
+ billing: "B",
37
+ delivery: "D"
38
+ }
39
+
40
+ SEX = {
41
+ male: "M",
42
+ female: "F"
43
+ }
44
+
45
+ MARITAL_STATUS = {
46
+ single: "S",
47
+ married: "M",
48
+ separated: "A",
49
+ divorced: "D",
50
+ widowed: "W"
51
+ }
52
+ end
53
+ end
@@ -0,0 +1,22 @@
1
+ # encoding: UTF-8
2
+ class Hash
3
+ def symbolize_all_keys!
4
+ symbolize_all_keys_in self
5
+ end
6
+
7
+ private
8
+
9
+ def symbolize_all_keys_in(hash)
10
+ case
11
+ when hash.is_a?(Array)
12
+ hash.each { |value| symbolize_all_keys_in(value) }
13
+ when hash.is_a?(Hash)
14
+ hash.symbolize_keys!
15
+
16
+ hash.each_value do |value|
17
+ value.symbolize_keys! if value.is_a?(Hash)
18
+ symbolize_all_keys_in(value)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -5,48 +5,94 @@ module Tray
5
5
  module Checkout
6
6
  class Parser
7
7
  def response(xml)
8
- puts xml
9
- hash = convert_to_hash(xml)
10
- success?(hash) ? data(hash) : errors(hash)
8
+ create_response_from(xml)
9
+ success? ? data : errors
10
+ end
11
+
12
+ def payment_params!(params)
13
+ customer_params_types! params[:customer]
14
+ payment_params_types! params[:payment]
15
+
16
+ params
11
17
  end
12
18
 
13
19
  private
14
20
 
15
- def convert_to_hash(xml)
16
- symbolize_all_keys!(Hash.from_xml(xml))[:transaction]
21
+ def customer_params_types!(customer)
22
+ return unless customer
23
+ customer[:gender] = SEX[customer[:sex]] if customer[:sex]
24
+ customer[:relationship] = MARITAL_STATUS[customer[:marital_status]] if customer[:marital_status]
25
+ contacts_params_types! customer[:contacts]
26
+ addresses_params_types! customer[:addresses]
17
27
  end
18
28
 
19
- def success?(hash)
20
- hash[:message_response][:message] == "success"
29
+ def payment_params_types!(payment)
30
+ return unless payment
31
+ payment[:payment_method_id] = PAYMENT_METHOD[payment[:payment_method]] if payment[:payment_method]
32
+ end
33
+
34
+ def contacts_params_types!(contacts)
35
+ return unless contacts
36
+
37
+ contacts.each do |contact|
38
+ contact[:type_contact] = CONTACT_TYPE[contact[:contact_type]] if contact[:contact_type]
39
+ end
21
40
  end
22
41
 
23
- def data(hash)
24
- hash[:data_response]
42
+ def addresses_params_types!(addresses)
43
+ return unless addresses
44
+
45
+ addresses.each do |address|
46
+ address[:type_address] = ADDRESS_TYPE[address[:address_type]] if address[:address_type]
47
+ end
25
48
  end
26
49
 
27
- def errors(hash)
28
- hash[:error_response]
50
+ def create_response_from(xml)
51
+ @response = Hash.from_xml(xml).symbolize_all_keys![:transaction]
29
52
  end
30
53
 
31
- def symbolize_all_keys!(hash)
32
- #TODO: Move to Hash class.
33
- case
34
- when hash.is_a?(Array)
35
- puts "### Array #{hash}"
36
- puts
37
- hash.each { |value| symbolize_all_keys!(value) }
38
- when hash.is_a?(Hash)
39
- puts "$$$ Hash: #{hash}"
40
- puts
41
- hash.symbolize_keys!
54
+ def success?
55
+ @response[:message_response][:message] == "success"
56
+ end
42
57
 
43
- hash.each_value do |value|
44
- value.symbolize_keys! if value.is_a?(Hash)
45
- symbolize_all_keys!(value)
46
- end
58
+ def data
59
+ data_response = @response[:data_response][:transaction]
60
+ transaction_response_types! data_response
61
+ payment_response_types! data_response
62
+ date_to_time! data_response
63
+ data_response[:success] = true
64
+ data_response
65
+ end
66
+
67
+ def transaction_response_types!(transaction)
68
+ transaction[:payment_method] = PAYMENT_METHOD.invert[transaction[:payment_method_id]]
69
+ transaction[:status] = TRANSACTION_STATUS.invert[transaction[:status_id]]
70
+ end
71
+
72
+ def payment_response_types!(transaction)
73
+ payment = transaction[:payment]
74
+ payment[:payment_method] = PAYMENT_METHOD.invert[payment[:payment_method_id]]
75
+ end
76
+
77
+ def errors
78
+ error_response = @response[:error_response]
79
+
80
+ if error_response[:validation_errors]
81
+ error_response[:errors] = error_response.delete(:validation_errors)
47
82
  end
48
83
 
49
- hash
84
+ error_response[:success] = false
85
+ error_response
86
+ end
87
+
88
+ def date_to_time!(hash)
89
+ hash.each do |key, value|
90
+ date_to_time!(value) if value.is_a?(Hash)
91
+
92
+ if key.to_s.starts_with?("date_") && value
93
+ hash[key] = (value.to_time rescue value) || value
94
+ end
95
+ end
50
96
  end
51
97
  end
52
98
  end
@@ -6,8 +6,12 @@ module Tray
6
6
 
7
7
  def get(token)
8
8
  response = web_service.request!("#{URL}/get_by_token", { token: token })
9
- result = parser.response(response)
10
- result
9
+ parser.response(response)
10
+ end
11
+
12
+ def create(params)
13
+ response = web_service.request!("#{URL}/pay_complete", parser.payment_params!(params))
14
+ parser.response(response)
11
15
  end
12
16
 
13
17
  private
@@ -1,7 +1,7 @@
1
1
  # encoding: UTF-8
2
2
  module Tray
3
3
  module Checkout
4
- VERSION = "0.0.0"
4
+ VERSION = "0.0.1"
5
5
  end
6
6
  end
7
7
 
@@ -1,4 +1,5 @@
1
1
  # encoding: UTF-8
2
+ require 'active_support/core_ext'
2
3
  require 'net/http'
3
4
  require 'uri'
4
5
 
@@ -24,7 +25,7 @@ module Tray
24
25
 
25
26
  def build_request(uri, params)
26
27
  request = Net::HTTP::Post.new(uri.path)
27
- request.set_form_data(params)
28
+ request.body = params.to_param
28
29
  request
29
30
  end
30
31
  end
data/lib/tray-checkout.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  # encoding: UTF-8
2
2
  require 'rubygems'
3
3
  require 'tray/checkout'
4
+ require 'tray/checkout/constants'
5
+ require 'tray/checkout/hash'
4
6
  require 'tray/checkout/parser'
5
7
  require 'tray/checkout/transaction'
6
8
  require 'tray/checkout/web_service'
@@ -0,0 +1,23 @@
1
+ # encoding: UTF-8
2
+
3
+ def mock_request_for(response)
4
+ url = Regexp.new(Tray::Checkout::Transaction::URL)
5
+ WebMock::API.stub_request(:post, url).to_return(:status => 200, :body => body_for(response))
6
+ end
7
+
8
+ def body_for(response)
9
+ case response
10
+ when :get_success_boleto,
11
+ :get_failure_not_found,
12
+ :create_success_boleto,
13
+ :create_success_mastercard,
14
+ :create_failure_validation_errors
15
+ read_file_for(response)
16
+ else
17
+ response
18
+ end
19
+ end
20
+
21
+ def read_file_for(filename)
22
+ File.open("#{File.dirname(__FILE__)}/responses/#{filename}.xml").read
23
+ end
@@ -0,0 +1,51 @@
1
+ <transaction>
2
+ <message_response>
3
+ <message>error</message>
4
+ </message_response>
5
+ <error_response>
6
+ <validation_errors type="array">
7
+ <validation_error>
8
+ <code>1</code>
9
+ <message_complete>Tipo n&#227;o pode ficar em branco</message_complete>
10
+ <message>n&#227;o pode ficar em branco</message>
11
+ <field>person_addresses.type_address</field>
12
+ </validation_error>
13
+ <validation_error>
14
+ <code>1</code>
15
+ <message_complete>Logradouro (Rua, Av, Travessa...) n&#227;o pode ficar em branco</message_complete>
16
+ <message>n&#227;o pode ficar em branco</message>
17
+ <field>person_addresses.street</field>
18
+ </validation_error>
19
+ <validation_error>
20
+ <code>1</code>
21
+ <message_complete>Cep n&#227;o pode ficar em branco</message_complete>
22
+ <message>n&#227;o pode ficar em branco</message>
23
+ <field>person_addresses.postal_code</field>
24
+ </validation_error>
25
+ <validation_error>
26
+ <code>1</code>
27
+ <message_complete>Cidade n&#227;o pode ficar em branco</message_complete>
28
+ <message>n&#227;o pode ficar em branco</message>
29
+ <field>person_addresses.city</field>
30
+ </validation_error>
31
+ <validation_error>
32
+ <code>1</code>
33
+ <message_complete>UF n&#227;o pode ficar em branco</message_complete>
34
+ <message>n&#227;o pode ficar em branco</message>
35
+ <field>person_addresses.state</field>
36
+ </validation_error>
37
+ <validation_error>
38
+ <code>1</code>
39
+ <message_complete>N&#250;mero, Lote n&#227;o pode ficar em branco</message_complete>
40
+ <message>n&#227;o pode ficar em branco</message>
41
+ <field>person_addresses.number</field>
42
+ </validation_error>
43
+ <validation_error>
44
+ <code>1</code>
45
+ <message_complete>Bairro n&#227;o pode ficar em branco</message_complete>
46
+ <message>n&#227;o pode ficar em branco</message>
47
+ <field>person_addresses.neighborhood</field>
48
+ </validation_error>
49
+ </validation_errors>
50
+ </error_response>
51
+ </transaction>