clearsale 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ *.sw*
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,98 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ clearsale (0.0.1)
5
+ builder
6
+ savon
7
+
8
+ GEM
9
+ remote: http://rubygems.org/
10
+ specs:
11
+ active_support (3.0.0)
12
+ activesupport (= 3.0.0)
13
+ activesupport (3.0.0)
14
+ addressable (2.2.8)
15
+ akami (1.2.0)
16
+ gyoku (>= 0.4.0)
17
+ nokogiri (>= 1.4.0)
18
+ builder (3.0.0)
19
+ columnize (0.3.6)
20
+ crack (0.3.1)
21
+ curb (0.8.1)
22
+ debugger (1.2.0)
23
+ columnize (>= 0.3.1)
24
+ debugger-linecache (~> 1.1.1)
25
+ debugger-ruby_core_source (~> 1.1.3)
26
+ debugger-linecache (1.1.2)
27
+ debugger-ruby_core_source (>= 1.1.1)
28
+ debugger-ruby_core_source (1.1.3)
29
+ diff-lcs (1.1.3)
30
+ ffi (1.0.11)
31
+ guard (1.2.3)
32
+ listen (>= 0.4.2)
33
+ thor (>= 0.14.6)
34
+ guard-bundler (1.0.0)
35
+ bundler (~> 1.0)
36
+ guard (~> 1.1)
37
+ guard-rspec (1.2.0)
38
+ guard (>= 1.1)
39
+ gyoku (0.4.6)
40
+ builder (>= 2.1.2)
41
+ httpi (1.1.1)
42
+ rack
43
+ i18n (0.6.0)
44
+ listen (0.4.7)
45
+ rb-fchange (~> 0.0.5)
46
+ rb-fsevent (~> 0.9.1)
47
+ rb-inotify (~> 0.8.8)
48
+ nokogiri (1.5.5)
49
+ nori (1.1.3)
50
+ rack (1.4.1)
51
+ rake (0.9.2.2)
52
+ rb-fchange (0.0.5)
53
+ ffi
54
+ rb-fsevent (0.9.1)
55
+ rb-inotify (0.8.8)
56
+ ffi (>= 0.5.0)
57
+ rspec (2.10.0)
58
+ rspec-core (~> 2.10.0)
59
+ rspec-expectations (~> 2.10.0)
60
+ rspec-mocks (~> 2.10.0)
61
+ rspec-core (2.10.1)
62
+ rspec-expectations (2.10.0)
63
+ diff-lcs (~> 1.1.3)
64
+ rspec-mocks (2.10.1)
65
+ savon (1.1.0)
66
+ akami (~> 1.2.0)
67
+ builder (>= 2.1.2)
68
+ gyoku (~> 0.4.5)
69
+ httpi (~> 1.1.0)
70
+ nokogiri (>= 1.4.0)
71
+ nori (~> 1.1.0)
72
+ wasabi (~> 2.5.0)
73
+ thor (0.15.4)
74
+ timecop (0.4.1)
75
+ vcr (1.11.3)
76
+ wasabi (2.5.0)
77
+ httpi (~> 1.0)
78
+ nokogiri (>= 1.4.0)
79
+ webmock (1.7.10)
80
+ addressable (~> 2.2, > 2.2.5)
81
+ crack (>= 0.1.7)
82
+
83
+ PLATFORMS
84
+ ruby
85
+
86
+ DEPENDENCIES
87
+ active_support
88
+ clearsale!
89
+ curb
90
+ debugger
91
+ guard-bundler
92
+ guard-rspec
93
+ i18n
94
+ rake
95
+ rspec
96
+ timecop
97
+ vcr (~> 1.11.3)
98
+ webmock (~> 1.7.0)
data/Guardfile ADDED
@@ -0,0 +1,10 @@
1
+ guard 'bundler' do
2
+ watch('Gemfile')
3
+ end
4
+
5
+ guard 'rspec', :version => 2, :bundler => false do
6
+ watch(%r{^spec/(.*)_spec\.rb$})
7
+ watch(%r{^lib/clearsale.rb$}) { "spec" }
8
+ watch(%r{^lib/clearsale/(.*)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
9
+ watch('spec/spec_helper.rb') { "spec" }
10
+ end
data/README.rdoc ADDED
@@ -0,0 +1,107 @@
1
+ = Clearsale
2
+
3
+ == Instalação
4
+ Defina a variavél de ambiente CLEARSALE_ENTITYCODE
5
+ export CLEARSALE_ENTITYCODE=03524C82-F434-4A32-8D34-EFFF2023341B
6
+
7
+ Adicione no seu Gemfile
8
+ gem 'clearsale', :github => 'Baby-com-br/clearsale'
9
+
10
+ Execute
11
+ bundle install
12
+
13
+ == Uso
14
+ require 'clearsale'
15
+
16
+ order = {
17
+ :id => 1234,
18
+ :paid_at => 2.seconds.ago,
19
+ :billing_address => {
20
+ :street_name => 'Bla St',
21
+ :number => '123',
22
+ :complement => '',
23
+ :neighborhood => 'Rhode Island',
24
+ :city => 'Mayland',
25
+ :state => 'Maryland',
26
+ :postal_code => '00100-011'
27
+ },
28
+ :shipping_address => {
29
+ :street_name => 'Bla St',
30
+ :number => '123',
31
+ :complement => '',
32
+ :neighborhood => 'Rhode Island',
33
+ :city => 'Mayland',
34
+ :state => 'Maryland',
35
+ :postal_code => '00100-011'
36
+ },
37
+ :installments => 3,
38
+ :total_items => 20.00,
39
+ :total_order => 25.00,
40
+ :items_count => 3,
41
+ :created_at => Time.current,
42
+ :order_items => [
43
+ {
44
+ :product => {
45
+ :id => 5555,
46
+ :name => 'Pogobol',
47
+ :category => { :id => 7777, :name => 'Disney' }
48
+ },
49
+ :price => 5.00,
50
+ :quantity => 2,
51
+ },
52
+ {
53
+ :product => {
54
+ :id => 5555,
55
+ :name => 'Pogobol',
56
+ :category => { :id => 7777, :name => 'Disney' }
57
+ },
58
+ :price => 5.00,
59
+ :quantity => 2,
60
+ },
61
+ ],
62
+ }
63
+
64
+ payment = {
65
+ :card_holder => 'Petter L Griffin',
66
+ :card_number => '1234432111112222',
67
+ :card_expiration => '05/2012',
68
+ :card_security_code => '123',
69
+ :acquirer => 'visa',
70
+ :amount => 50.00,
71
+ }
72
+
73
+ user = {
74
+ :email => 'petergriffin@abc.com',
75
+ :id => 8888,
76
+ :cpf => '248.783.463-37',
77
+ :full_name => 'Peter Löwenbräu Griffin',
78
+ :birthdate => 40.years.ago,
79
+ :phone => '11 8001 1002',
80
+ :gender => 'm',
81
+ :last_sign_in_ip => '127.0.0.1',
82
+ }
83
+
84
+ #Solicitando a analise
85
+ response = Clearsale::Analysis.send_order(order, payment, user)
86
+
87
+ #consultando a analise
88
+ order_id = '1234'
89
+ response = Clearsale::Analysis.get_order_status(order_id)
90
+
91
+ response.order_id
92
+ # => 1234
93
+
94
+ response.score
95
+ # => (0.01..21.11)
96
+
97
+ response.status
98
+ # => :automatic_approval
99
+ # => :manual_approval
100
+ # => :rejected_without_suspicion
101
+ # => :manual_analysis
102
+ # => :error
103
+ # => :waiting
104
+ # => :manual_rejection
105
+ # => :cancelled
106
+ # => :fraud
107
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/clearsale.gemspec ADDED
@@ -0,0 +1,34 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "clearsale/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "clearsale"
7
+ s.version = Clearsale::VERSION
8
+ s.authors = ["Daniel Konishi"]
9
+ s.email = %w[dkonishi@gmail.com]
10
+ s.homepage = "http://github.com/Baby-com-br/clearsale"
11
+ s.summary = "clearsale gem to use Clearsale service"
12
+ s.description = "clearsale gem to use Clearsale service"
13
+
14
+ s.rubyforge_project = "clearsale"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+ s.add_dependency "builder"
21
+ s.add_dependency "savon"
22
+
23
+ s.add_development_dependency "rake"
24
+ s.add_development_dependency "rspec"
25
+ s.add_development_dependency "webmock", "~> 1.7.0"
26
+ s.add_development_dependency "vcr", "~> 1.11.3"
27
+ s.add_development_dependency "guard-rspec"
28
+ s.add_development_dependency "guard-bundler"
29
+ s.add_development_dependency "debugger"
30
+ s.add_development_dependency "active_support"
31
+ s.add_development_dependency "i18n"
32
+ s.add_development_dependency "curb"
33
+ s.add_development_dependency "timecop"
34
+ end
data/lib/clearsale.rb ADDED
@@ -0,0 +1,11 @@
1
+ require 'active_support/all'
2
+
3
+ module Clearsale
4
+ extend ActiveSupport::Autoload
5
+
6
+ autoload :Object, 'clearsale/object'
7
+ autoload :Order, 'clearsale/order'
8
+ autoload :OrderResponse, 'clearsale/order_response'
9
+ autoload :Connector, 'clearsale/connector'
10
+ autoload :Analysis, 'clearsale/analysis'
11
+ end
@@ -0,0 +1,27 @@
1
+ module Clearsale
2
+ class Analysis
3
+ def self.connector
4
+ @connector ||= Clearsale::Connector.build
5
+ end
6
+
7
+ def self.send_order(order_hash, payment_hash, user_hash)
8
+ order = Object.new(order_hash)
9
+ payment = Object.new(payment_hash)
10
+ user = Object.new(user_hash)
11
+
12
+ order_xml = Clearsale::Order.to_xml(order, payment, user)
13
+ request = {"xml" => order_xml}
14
+
15
+ OrderResponse.build_from_send_order(connector.do_request('SendOrders', request))
16
+ end
17
+
18
+ def self.clear_connector
19
+ @connector = nil
20
+ end
21
+
22
+ def self.get_order_status(order_id)
23
+ request = {'orderID' => order_id}
24
+ OrderResponse.build_from_update(connector.do_request('GetOrderStatus', request))
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,63 @@
1
+ require 'savon'
2
+ require 'nori'
3
+
4
+ Nori.parser = :nokogiri
5
+
6
+ module Clearsale
7
+ class Connector
8
+ NAMESPACE = "http://www.clearsale.com.br/integration"
9
+
10
+ URLs = {
11
+ :homolog => 'http://homologacao.clearsale.com.br/Integracaov2/Service.asmx',
12
+ :production => 'https://www.clearsale.com.br/integracaov2/service.asmx'
13
+ }
14
+
15
+ def self.build(env = ENV['CLEARSALE_ENV'])
16
+ if env == "production"
17
+ new(URLs[:production])
18
+ else
19
+ new(URLs[:homolog])
20
+ end
21
+ end
22
+
23
+ def initialize(endpoint_url)
24
+ @token = ENV['CLEARSALE_ENTITYCODE']
25
+ @client = Savon::Client.new do |wsdl|
26
+ wsdl.endpoint = endpoint_url
27
+ wsdl.namespace = NAMESPACE
28
+ end
29
+ end
30
+
31
+ def do_request(method, request)
32
+ namespaced_request = append_namespace('int', request)
33
+ arguments = namespaced_request.merge({'int:entityCode' => @token})
34
+
35
+ response = @client.request(:int, method) do |soap, _, http, _|
36
+ soap.namespaces = {
37
+ 'xmlns:soap' => "http://www.w3.org/2003/05/soap-envelope",
38
+ 'xmlns:xsd' => "http://www.w3.org/2001/XMLSchema" ,
39
+ 'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance" ,
40
+ 'xmlns:int' => "http://www.clearsale.com.br/integration",
41
+ }
42
+
43
+ soap.env_namespace = :soap
44
+
45
+ soap.body = arguments
46
+ http.headers['SOAPAction'] = "#{NAMESPACE}/#{method}"
47
+ end
48
+
49
+ extract_response_xml(method, response.to_hash)
50
+ end
51
+
52
+ def extract_response_xml(method, response)
53
+ results = response.fetch(:"#{method.snakecase}_response", {})
54
+ response_xml = results.fetch(:"#{method.snakecase}_result", {}).to_s
55
+
56
+ Nori.parse(response_xml.gsub(/^<\?xml.*\?>/, ''))
57
+ end
58
+
59
+ def append_namespace(namespace, hash)
60
+ Hash[hash.map {|key, value| ["#{namespace}:#{key}", value]}]
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,27 @@
1
+ require 'ostruct'
2
+
3
+ module Clearsale
4
+ class Object < OpenStruct
5
+ def new_ostruct_member(name)
6
+ name = name.to_sym
7
+ unless self.respond_to?(name)
8
+ class << self; self; end.class_eval do
9
+ define_method(name) {
10
+ v = @table[name]
11
+ case v
12
+ when Hash
13
+ Object.new(v)
14
+ when Array
15
+ v.each_with_index { |item, index| v[index] = Object.new(item) }
16
+ else
17
+ v
18
+ end
19
+ }
20
+ define_method("#{name}=") { |x| modifiable[name] = x }
21
+ define_method("#{name}_as_a_hash") { @table[name] }
22
+ end
23
+ end
24
+ name
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,122 @@
1
+ require 'builder'
2
+ require 'ostruct'
3
+
4
+ module Clearsale
5
+ class Order
6
+ CARD_TYPE_MAP = {
7
+ :visa => 3,
8
+ :mastercard => 2,
9
+ :amex => 5,
10
+ }
11
+ def self.to_xml(order, payment, user)
12
+ builder = Builder::XmlMarkup.new
13
+ xml = builder.tag!("ClearSale") do |b|
14
+ b.tag!('Orders') do |b|
15
+ b.tag!('Order') do |b|
16
+ build_order(b, order, payment, user)
17
+ end
18
+ end
19
+ end.to_s
20
+ xml
21
+ end
22
+
23
+ def self.build_order(builder, order, payment, user)
24
+ builder.tag!('ID', order.id)
25
+ builder.tag!('Date', order.created_at.strftime("%Y-%m-%dT%H:%M:%S"))
26
+ builder.tag!('Email', user.email)
27
+ builder.tag!('TotalItens', order.total_items)
28
+ builder.tag!('TotalOrder', order.total_order)
29
+ builder.tag!('QtyInstallments', order.installments)
30
+ builder.tag!('QtyItems', order.items_count)
31
+ builder.tag!('IP', user.last_sign_in_ip)
32
+ builder.tag!('CollectionData') do |b|
33
+ build_user_data(b, user, order.billing_address)
34
+ end
35
+ builder.tag!('ShippingData') do |b|
36
+ build_user_data(b, user, order.shipping_address)
37
+ end
38
+
39
+ builder.tag!('Payments') do |b|
40
+ build_payment_data(b, order, payment, user)
41
+ end
42
+
43
+ builder.tag!('Items') do |b|
44
+ order.order_items.each do |order_item|
45
+ build_item(b, order_item)
46
+ end
47
+ end
48
+ end
49
+
50
+ def self.build_user_data(builder, user, billing_address)
51
+ builder.tag!('ID', user.id)
52
+ builder.tag!('Type', 1) # Pessoa Física
53
+ builder.tag!('LegalDocument1', user.cpf.gsub(/[\.\-]*/, '').strip)
54
+ builder.tag!('Name', user.full_name)
55
+ builder.tag!('BirthDate', user.birthdate.to_time.strftime("%Y-%m-%dT%H:%M:%S"))
56
+ builder.tag!('Email', user.email)
57
+ builder.tag!('Genre', user.gender.downcase)
58
+ build_address(builder, billing_address)
59
+ builder.tag!('Phones') do |b|
60
+ build_phone(b, user)
61
+ end
62
+ end
63
+
64
+ def self.build_address(builder, address)
65
+ builder.tag!('Address') do |b|
66
+ builder.tag!('Street', address.street_name)
67
+ builder.tag!('Number', address.number)
68
+ builder.tag!('Comp', address.complement)
69
+ builder.tag!('County', address.neighborhood)
70
+ builder.tag!('City', address.city)
71
+ builder.tag!('State', address.state)
72
+ builder.tag!('ZipCode', address.postal_code)
73
+ end
74
+ end
75
+
76
+ def self.build_phone(builder, user)
77
+ if user.phone.present?
78
+ stripped_phone = user.phone.gsub(/\(*\)*\s*\-*/, '')
79
+
80
+ builder.tag!('Phone') do |b|
81
+ b.tag!('Type', 0) # Undefined
82
+ b.tag!('DDD', stripped_phone[0..1])
83
+ b.tag!('Number', stripped_phone[2..-1])
84
+ end
85
+ end
86
+ end
87
+
88
+ def self.build_payment_data(builder, order, payment, user)
89
+ builder.tag!('Payment') do |b|
90
+ paid_at = order.paid_at || Time.current
91
+
92
+ b.tag!('Date', paid_at.strftime("%Y-%m-%dT%H:%M:%S"))
93
+ b.tag!('Amount', payment.amount)
94
+
95
+ #is_credit_card
96
+ b.tag!('PaymentTypeID', 1)
97
+
98
+ b.tag!('QtyInstallments', order.installments)
99
+
100
+ b.tag!('CardNumber', payment.card_number)
101
+ b.tag!('CardBin', payment.card_number[0..5])
102
+ b.tag!('CardType', CARD_TYPE_MAP.fetch(payment.acquirer, 4)) # Failover is 'outros'
103
+ b.tag!('CardExpirationDate', payment.card_expiration)
104
+ b.tag!('Name', payment.customer_name)
105
+ b.tag!('LegalDocument', user.cpf.gsub(/[\.\-]*/, '').strip)
106
+
107
+ build_address(b, order.billing_address)
108
+ end
109
+ end
110
+
111
+ def self.build_item(builder, order_item)
112
+ builder.tag!('Item') do |b|
113
+ b.tag!('ID', order_item.product.id)
114
+ b.tag!('Name', order_item.product.name)
115
+ b.tag!('ItemValue', order_item.price)
116
+ b.tag!('Qty', order_item.quantity)
117
+ b.tag!('CategoryID', order_item.product.category.id) if order_item.product.category.try(:id).present?
118
+ b.tag!('CategoryName', order_item.product.category.name) if order_item.product.category.try(:name).present?
119
+ end
120
+ end
121
+ end
122
+ end