webpay_rails 1.0.3 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -2
  3. data/.travis.yml +4 -0
  4. data/CHANGELOG.md +14 -0
  5. data/Gemfile +2 -0
  6. data/README.md +32 -7
  7. data/config.ru +7 -0
  8. data/lib/webpay_rails.rb +5 -0
  9. data/lib/webpay_rails/base.rb +107 -32
  10. data/lib/webpay_rails/errors.rb +46 -8
  11. data/lib/webpay_rails/soap.rb +28 -51
  12. data/lib/webpay_rails/soap_normal.rb +52 -0
  13. data/lib/webpay_rails/soap_nullify.rb +32 -0
  14. data/lib/webpay_rails/transaction.rb +4 -11
  15. data/lib/webpay_rails/transaction_base.rb +11 -0
  16. data/lib/webpay_rails/transaction_nullified.rb +18 -0
  17. data/lib/webpay_rails/transaction_result.rb +5 -13
  18. data/lib/webpay_rails/vault.rb +36 -0
  19. data/lib/webpay_rails/version.rb +1 -1
  20. data/spec/internal/app/controllers/orders_controller.rb +107 -0
  21. data/spec/internal/app/models/concerns/universally_unique_identifiable.rb +15 -0
  22. data/spec/internal/app/models/order.rb +17 -0
  23. data/spec/internal/app/models/order_blank.rb +4 -0
  24. data/spec/internal/app/models/order_invalid.rb +14 -0
  25. data/spec/internal/app/views/orders/failed.html.erb +1 -0
  26. data/spec/internal/app/views/orders/gateway.html.erb +8 -0
  27. data/spec/internal/app/views/orders/new.html.erb +6 -0
  28. data/spec/internal/app/views/orders/success.html.erb +18 -0
  29. data/spec/internal/config/database.yml +3 -0
  30. data/spec/internal/config/routes.rb +10 -0
  31. data/spec/internal/db/schema.rb +22 -0
  32. data/spec/internal/public/favicon.ico +0 -0
  33. data/spec/internal/vendor/vault/597020000541.crt +22 -0
  34. data/spec/internal/vendor/vault/597020000541.key +27 -0
  35. data/spec/internal/vendor/vault/tbk.pem +17 -0
  36. data/spec/spec_helper.rb +31 -4
  37. data/spec/vault_helper.rb +67 -0
  38. data/spec/webpay_rails_spec.rb +296 -185
  39. data/webpay_rails.gemspec +18 -12
  40. metadata +162 -6
@@ -0,0 +1,52 @@
1
+ module WebpayRails
2
+ class SoapNormal < Soap
3
+ def init_transaction(args)
4
+ request = client.build_request(:init_transaction,
5
+ message: init_transaction_message(args))
6
+
7
+ call(request, :init_transaction)
8
+ end
9
+
10
+ def get_transaction_result(args)
11
+ request = client.build_request(:get_transaction_result,
12
+ message: { tokenInput: args[:token] })
13
+
14
+ call(request, :get_transaction_result)
15
+ end
16
+
17
+ def acknowledge_transaction(args)
18
+ request = client.build_request(:acknowledge_transaction,
19
+ message: { tokenInput: args[:token] })
20
+
21
+ call(request, :acknowledge_transaction)
22
+ end
23
+
24
+ private
25
+
26
+ def wsdl_path
27
+ case @environment
28
+ when :production
29
+ 'https://webpay3g.transbank.cl/WSWebpayTransaction/cxf/WSWebpayService?wsdl'
30
+ when :certification, :integration
31
+ 'https://webpay3gint.transbank.cl/WSWebpayTransaction/cxf/WSWebpayService?wsdl'
32
+ end
33
+ end
34
+
35
+ def init_transaction_message(args)
36
+ {
37
+ wsInitTransactionInput: {
38
+ wSTransactionType: 'TR_NORMAL_WS',
39
+ buyOrder: args[:buy_order],
40
+ sessionId: args[:session_id],
41
+ returnURL: args[:return_url],
42
+ finalURL: args[:final_url],
43
+ transactionDetails: {
44
+ amount: args[:amount],
45
+ commerceCode: @commerce_code,
46
+ buyOrder: args[:buy_order]
47
+ }
48
+ }
49
+ }
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,32 @@
1
+ module WebpayRails
2
+ class SoapNullify < Soap
3
+ def nullify(args)
4
+ request = client.build_request(:nullify, message: nullify_message(args))
5
+
6
+ call(request, :nullify)
7
+ end
8
+
9
+ private
10
+
11
+ def wsdl_path
12
+ case @environment
13
+ when :production
14
+ 'https://webpay3g.transbank.cl/WSWebpayTransaction/cxf/WSCommerceIntegrationService?wsdl'
15
+ when :certification, :integration
16
+ 'https://webpay3gint.transbank.cl/WSWebpayTransaction/cxf/WSCommerceIntegrationService?wsdl'
17
+ end
18
+ end
19
+
20
+ def nullify_message(args)
21
+ {
22
+ nullificationInput: {
23
+ authorizationCode: args[:authorization_code],
24
+ authorizedAmount: args[:authorized_amount],
25
+ buyOrder: args[:buy_order],
26
+ commerceId: @commerce_code,
27
+ nullifyAmount: args[:nullify_amount]
28
+ }
29
+ }
30
+ end
31
+ end
32
+ end
@@ -1,24 +1,17 @@
1
1
  module WebpayRails
2
- class Transaction
2
+ class Transaction < TransactionBase
3
3
  def self.attr_list
4
4
  [:token, :url]
5
5
  end
6
6
 
7
- def initialize(document)
8
- self.class.attr_list.each do |k|
9
- v = document.at_xpath("//#{k.to_s.tr('_', '')}")
10
- send("#{k}=", v.text.to_s) unless v.nil?
11
- end
12
- end
13
-
14
7
  def success?
15
8
  !token.blank?
16
9
  end
17
10
 
18
- attr_reader *attr_list
11
+ attr_reader(*attr_list)
19
12
 
20
- private
13
+ private
21
14
 
22
- attr_writer *attr_list
15
+ attr_writer(*attr_list)
23
16
  end
24
17
  end
@@ -0,0 +1,11 @@
1
+ module WebpayRails
2
+ class TransactionBase
3
+ def initialize(response)
4
+ document = Nokogiri::HTML(response.to_s)
5
+ self.class.attr_list.each do |k|
6
+ v = document.at_xpath("//#{k.to_s.tr('_', '')}")
7
+ send("#{k}=", v.text.to_s) unless v.nil?
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ module WebpayRails
2
+ class TransactionNullified < TransactionBase
3
+ def self.attr_list
4
+ [:token, :authorization_code, :authorization_date, :balance,
5
+ :nullified_amount]
6
+ end
7
+
8
+ def success?
9
+ !token.blank?
10
+ end
11
+
12
+ attr_reader(*attr_list)
13
+
14
+ private
15
+
16
+ attr_writer(*attr_list)
17
+ end
18
+ end
@@ -1,6 +1,5 @@
1
1
  module WebpayRails
2
- class TransactionResult
3
-
2
+ class TransactionResult < TransactionBase
4
3
  def self.attr_list
5
4
  [
6
5
  :buy_order, :session_id, :accounting_date, :transaction_date, :vci,
@@ -15,21 +14,14 @@ module WebpayRails
15
14
  ]
16
15
  end
17
16
 
18
- def initialize(document)
19
- self.class.attr_list.each do |k|
20
- v = document.at_xpath("//#{k.to_s.tr('_', '')}")
21
- send("#{k}=", v.text.to_s) unless v.nil?
22
- end
23
- end
24
-
25
17
  def approved?
26
- response_code.to_i == 0
18
+ response_code.to_i.zero?
27
19
  end
28
20
 
29
- attr_reader *attr_list
21
+ attr_reader(*attr_list)
30
22
 
31
- private
23
+ private
32
24
 
33
- attr_writer *attr_list
25
+ attr_writer(*attr_list)
34
26
  end
35
27
  end
@@ -0,0 +1,36 @@
1
+ module WebpayRails
2
+ class Vault
3
+ def initialize(args)
4
+ args.map { |k, v| send("#{k}=", v) if respond_to? k }
5
+
6
+ raise WebpayRails::MissingPrivateKey unless @private_key
7
+ raise WebpayRails::MissingWebpayCertificate unless @webpay_cert
8
+ raise WebpayRails::MissingPublicCertificate unless @public_cert
9
+ end
10
+
11
+ attr_reader :webpay_cert, :private_key, :public_cert
12
+
13
+ private
14
+
15
+ def webpay_cert=(cert)
16
+ @webpay_cert ||= OpenSSL::X509::Certificate.new(read(cert))
17
+ end
18
+
19
+ def private_key=(key)
20
+ @private_key ||= OpenSSL::PKey::RSA.new(read(key))
21
+ end
22
+
23
+ def public_cert=(cert)
24
+ @public_cert ||= OpenSSL::X509::Certificate.new(read(cert))
25
+ end
26
+
27
+ def read(val)
28
+ return val if val.include? '-----BEGIN'
29
+
30
+ path = Pathname.new(val)
31
+ return path.read if path.file?
32
+
33
+ raise WebpayRails::FileNotFound, val
34
+ end
35
+ end
36
+ end
@@ -1,3 +1,3 @@
1
1
  module WebpayRails
2
- VERSION = "1.0.3".freeze
2
+ VERSION = '1.1.0'.freeze
3
3
  end
@@ -0,0 +1,107 @@
1
+ class OrdersController < ActionController::Base
2
+ before_action :find_order, only: [:return, :final]
3
+ before_action :verify_order, only: :return
4
+
5
+ def new
6
+ @order = Order.new
7
+ end
8
+
9
+ def create
10
+ @order = Order.new(create_params)
11
+
12
+ if @order.save
13
+ if init_transaction
14
+ render :gateway
15
+ else
16
+ @order.update(status: :failed)
17
+ render :failed
18
+ end
19
+ else
20
+ render action: :new
21
+ end
22
+ end
23
+
24
+ def return
25
+ if transaction_result && @order.update(update_params) && @result.approved?
26
+ @method = :get
27
+ @url = @result.url_redirection
28
+ @token = params[:token_ws]
29
+ @order.update(status: :approved)
30
+ render :gateway
31
+ else
32
+ @order.update(status: :failed)
33
+ render :failed
34
+ end
35
+ end
36
+
37
+ def final
38
+ if @order.approved?
39
+ render :success
40
+ else
41
+ render :failed
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def find_order
48
+ @order = Order.find(params[:id])
49
+ end
50
+
51
+ def create_params
52
+ params.require(:order).permit(:amount)
53
+ end
54
+
55
+ def update_params
56
+ {
57
+ tbk_token_ws: params[:token_ws],
58
+ tbk_accounting_date: @result.accounting_date,
59
+ tbk_buy_order: @result.buy_order,
60
+ tbk_card_number: @result.card_number,
61
+ tbk_commerce_code: @result.commerce_code,
62
+ tbk_authorization_code: @result.authorization_code,
63
+ tbk_payment_type_code: @result.payment_type_code,
64
+ tbk_response_code: @result.response_code,
65
+ tbk_transaction_date: @result.transaction_date,
66
+ tbk_vci: @result.vci,
67
+ tbk_session_id: @result.session_id,
68
+ tbk_card_expiration_date: @result.card_expiration_date,
69
+ tbk_shares_number: @result.shares_number,
70
+ amount: @result.amount
71
+ }
72
+ end
73
+
74
+ def verify_order
75
+ render :failed if @order.approved?
76
+ end
77
+
78
+ def init_transaction
79
+ transaction = Order.init_transaction(init_transaction_params)
80
+ if transaction.success?
81
+ @method = :post
82
+ @url = transaction.url
83
+ @token = transaction.token
84
+ end
85
+
86
+ transaction.success?
87
+ rescue WebpayRails::SoapError
88
+ false
89
+ end
90
+
91
+ def transaction_result
92
+ @result = Order.transaction_result(token: params[:token_ws])
93
+ true
94
+ rescue WebpayRails::SoapError
95
+ false
96
+ end
97
+
98
+ def init_transaction_params
99
+ {
100
+ amount: @order.amount,
101
+ buy_order: @order.buy_order_for_transbank,
102
+ session_id: session.id,
103
+ return_url: url_for(action: :return, id: @order.id),
104
+ final_url: url_for(action: :final, id: @order.id)
105
+ }
106
+ end
107
+ end
@@ -0,0 +1,15 @@
1
+ module UniversallyUniqueIdentifiable
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ before_create :set_uuid
6
+ end
7
+
8
+ def set_uuid
9
+ assign_attributes(uuid: SecureRandom.uuid)
10
+ end
11
+
12
+ def buy_order_for_transbank
13
+ uuid.first(30).delete!('-')
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ class Order < ActiveRecord::Base
2
+ include UniversallyUniqueIdentifiable
3
+ extend WebpayRails
4
+
5
+ webpay_rails(
6
+ commerce_code: 597020000541,
7
+ private_key: Rails.root.join('vendor/vault/597020000541.key').to_s,
8
+ public_cert: Rails.root.join('vendor/vault/597020000541.crt').to_s,
9
+ webpay_cert: Rails.root.join('vendor/vault/tbk.pem').to_s
10
+ )
11
+
12
+ enum status: [:created, :approved, :failed, :canceled, :expired, :pending,
13
+ :refunded]
14
+
15
+ scope :approved, -> { where(status: Order.statuses[:approved]) }
16
+ scope :normal_selling, -> { where(tbk_payment_type_code: 'VN') }
17
+ end
@@ -0,0 +1,4 @@
1
+ class OrderBlank < ActiveRecord::Base
2
+ include UniversallyUniqueIdentifiable
3
+ extend WebpayRails
4
+ end
@@ -0,0 +1,14 @@
1
+ class OrderInvalid < ActiveRecord::Base
2
+ include UniversallyUniqueIdentifiable
3
+ extend WebpayRails
4
+
5
+ webpay_rails(
6
+ commerce_code: 597020000541,
7
+ private_key: Rails.root.join('vendor/vault/597020000541.key').to_s,
8
+ public_cert: Rails.root.join('vendor/vault/597020000541.crt').to_s,
9
+ webpay_cert: Rails.root.join('vendor/vault/597020000541.crt').to_s
10
+ )
11
+
12
+ enum status: [:created, :approved, :failed, :canceled, :expired, :pending,
13
+ :refunded]
14
+ end
@@ -0,0 +1 @@
1
+ <h1>Failed transaction</h1>
@@ -0,0 +1,8 @@
1
+ <%= form_tag(@url, method: @method, style: 'display: none;', id: 'gatewayForm') do %>
2
+ <%= hidden_field_tag(:token_ws, @token) %>
3
+ <%= submit_tag("Continuar a webpay") %>
4
+ <% end %>
5
+
6
+ <script>
7
+ document.getElementById('gatewayForm').submit();
8
+ </script>
@@ -0,0 +1,6 @@
1
+ <h1>Form</h1>
2
+
3
+ <%= form_for @order do |f| %>
4
+ <%= f.number_field :amount %>
5
+ <%= f.submit 'Purchase' %>
6
+ <% end %>
@@ -0,0 +1,18 @@
1
+ <h1>Success transaction</h1>
2
+
3
+ <p><strong>id</strong>: <%= @order.id %></p>
4
+ <p><strong>tbk_token_ws</strong>: <%= @order.tbk_token_ws %></p>
5
+ <p><strong>tbk_accounting_date</strong>: <%= @order.tbk_accounting_date %></p>
6
+ <p><strong>tbk_buy_order</strong>: <%= @order.tbk_buy_order %></p>
7
+ <p><strong>tbk_card_number</strong>: <%= @order.tbk_card_number %></p>
8
+ <p><strong>tbk_commerce_code</strong>: <%= @order.tbk_commerce_code %></p>
9
+ <p><strong>tbk_authorization_code</strong>: <%= @order.tbk_authorization_code %></p>
10
+ <p><strong>tbk_payment_type_code</strong>: <%= @order.tbk_payment_type_code %></p>
11
+ <p><strong>tbk_response_code</strong>: <%= @order.tbk_response_code %></p>
12
+ <p><strong>tbk_transaction_date</strong>: <%= @order.tbk_transaction_date %></p>
13
+ <p><strong>tbk_vci</strong>: <%= @order.tbk_vci %></p>
14
+ <p><strong>tbk_session_id</strong>: <%= @order.tbk_session_id %></p>
15
+ <p><strong>tbk_card_expiration_date</strong>: <%= @order.tbk_card_expiration_date %></p>
16
+ <p><strong>tbk_shares_number</strong>: <%= @order.tbk_shares_number %></p>
17
+ <p><strong>amount</strong>: <%= @order.amount %></p>
18
+ <p><strong>status</strong>: <%= @order.status %></p>
@@ -0,0 +1,3 @@
1
+ test:
2
+ adapter: sqlite3
3
+ database: db/combustion_test.sqlite3
@@ -0,0 +1,10 @@
1
+ Rails.application.routes.draw do
2
+ root to: 'orders#new'
3
+
4
+ resources :orders, only: [:new, :create] do
5
+ member do
6
+ post :return
7
+ post :final
8
+ end
9
+ end
10
+ end