webpay_rails 1.0.3 → 1.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.
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