├── spec
├── internal
│ ├── public
│ │ └── favicon.ico
│ ├── app
│ │ ├── models
│ │ │ ├── user.rb
│ │ │ ├── order
│ │ │ │ ├── blank.rb
│ │ │ │ ├── normal_invalid.rb
│ │ │ │ ├── normal.rb
│ │ │ │ └── oneclick.rb
│ │ │ └── concerns
│ │ │ │ ├── universally_unique_identifiable.rb
│ │ │ │ └── orderable.rb
│ │ ├── views
│ │ │ ├── normal_orders
│ │ │ │ ├── failed.html.erb
│ │ │ │ ├── new.html.erb
│ │ │ │ ├── gateway.html.erb
│ │ │ │ └── success.html.erb
│ │ │ ├── oneclick_orders
│ │ │ │ ├── failed.html.erb
│ │ │ │ ├── new.html.erb
│ │ │ │ └── success.html.erb
│ │ │ └── oneclick_inscriptions
│ │ │ │ ├── failed.html.erb
│ │ │ │ ├── new.html.erb
│ │ │ │ ├── gateway.html.erb
│ │ │ │ └── success.html.erb
│ │ └── controllers
│ │ │ ├── oneclick_inscriptions_controller.rb
│ │ │ ├── oneclick_orders_controller.rb
│ │ │ └── normal_orders_controller.rb
│ ├── config
│ │ ├── database.yml
│ │ └── routes.rb
│ ├── db
│ │ └── schema.rb
│ └── vendor
│ │ └── vault
│ │ ├── tbk.pem
│ │ ├── 597020000541.crt
│ │ ├── 597020000547.crt
│ │ ├── 597020000541.key
│ │ └── 597020000547.key
├── webpay_rails_spec.rb
├── spec_helper.rb
├── nullify_spec.rb
├── oneclick_spec.rb
├── vault_helper.rb
└── normal_spec.rb
├── .rspec
├── lib
├── webpay_rails
│ ├── version.rb
│ ├── railites.rb
│ ├── responses
│ │ ├── init_inscription.rb
│ │ ├── reverse.rb
│ │ ├── remove_user.rb
│ │ ├── init_transaction.rb
│ │ ├── transaction_nullify.rb
│ │ ├── finish_inscription.rb
│ │ ├── authorization.rb
│ │ └── transaction_result.rb
│ ├── response.rb
│ ├── soap_nullify.rb
│ ├── vault.rb
│ ├── soap_normal.rb
│ ├── errors.rb
│ ├── verifier.rb
│ ├── soap_oneclick.rb
│ ├── soap.rb
│ └── base.rb
└── webpay_rails.rb
├── CHANGELOG.md
├── config.ru
├── .gitignore
├── Rakefile
├── .travis.yml
├── Gemfile
├── MIT-LICENSE
├── webpay_rails.gemspec
└── README.md
/spec/internal/public/favicon.ico:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.rspec:
--------------------------------------------------------------------------------
1 | --color
2 | --format documentation
3 |
--------------------------------------------------------------------------------
/spec/internal/app/models/user.rb:
--------------------------------------------------------------------------------
1 | class User < ActiveRecord::Base
2 | end
3 |
--------------------------------------------------------------------------------
/spec/internal/app/views/normal_orders/failed.html.erb:
--------------------------------------------------------------------------------
1 |
Failed transaction
2 |
--------------------------------------------------------------------------------
/spec/internal/app/views/oneclick_orders/failed.html.erb:
--------------------------------------------------------------------------------
1 | Failed transaction
2 |
--------------------------------------------------------------------------------
/lib/webpay_rails/version.rb:
--------------------------------------------------------------------------------
1 | module WebpayRails
2 | VERSION = '1.1.1'.freeze
3 | end
4 |
--------------------------------------------------------------------------------
/spec/internal/app/views/oneclick_inscriptions/failed.html.erb:
--------------------------------------------------------------------------------
1 | Failed inscription
2 |
--------------------------------------------------------------------------------
/spec/internal/config/database.yml:
--------------------------------------------------------------------------------
1 | test:
2 | adapter: sqlite3
3 | database: db/combustion_test.sqlite3
4 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | See the [Releases section of our GitHub project](https://github.com/limcross/webpay_rails/releases) for changelogs for each release version of WebpayRails.
2 |
--------------------------------------------------------------------------------
/lib/webpay_rails/railites.rb:
--------------------------------------------------------------------------------
1 | module WebpayRails
2 | class Railties < ::Rails::Railtie
3 | initializer 'Rails logger' do
4 | WebpayRails.rails_logger = Rails.logger
5 | end
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/config.ru:
--------------------------------------------------------------------------------
1 | require 'rubygems'
2 | require 'bundler'
3 |
4 | Bundler.require :default, :development
5 |
6 | Combustion.initialize! :active_record, :action_controller, :action_view
7 | run Combustion::Application
8 |
--------------------------------------------------------------------------------
/spec/internal/app/models/order/blank.rb:
--------------------------------------------------------------------------------
1 | class Order::Blank < ActiveRecord::Base
2 | extend WebpayRails
3 | include Orderable
4 | include UniversallyUniqueIdentifiable
5 |
6 | self.table_name = 'orders'
7 | end
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | spec/internal/log/*
2 | spec/internal/tmp/*
3 | spec/internal/db/*.sqlite3
4 | spec/internal/db/log/*.log
5 | *~
6 | coverage/*
7 | *.sqlite3
8 | .bundle
9 | rdoc/*
10 | pkg
11 | log
12 | test/tmp/*
13 | *.gem
14 | Gemfile.lock
15 |
--------------------------------------------------------------------------------
/spec/internal/app/views/normal_orders/new.html.erb:
--------------------------------------------------------------------------------
1 | Form
2 |
3 | <%= form_for @order, url: url_for(action: :create, controller: :normal_orders) do |f| %>
4 | <%= f.number_field :amount %>
5 | <%= f.submit 'Purchase' %>
6 | <% end %>
7 |
--------------------------------------------------------------------------------
/spec/internal/app/views/oneclick_orders/new.html.erb:
--------------------------------------------------------------------------------
1 | Form
2 |
3 | <%= form_for @order, url: url_for(action: :create, controller: :oneclick_orders) do |f| %>
4 | <%= f.number_field :amount %>
5 | <%= f.submit 'Purchase' %>
6 | <% end %>
7 |
--------------------------------------------------------------------------------
/lib/webpay_rails/responses/init_inscription.rb:
--------------------------------------------------------------------------------
1 | module WebpayRails::Responses
2 | class InitInscription < WebpayRails::Response
3 | def self.attr_list
4 | [:token, :url_webpay]
5 | end
6 |
7 | attr_accessor(*attr_list)
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/internal/app/views/oneclick_inscriptions/new.html.erb:
--------------------------------------------------------------------------------
1 | Form
2 |
3 | <%= form_for @user, url: url_for(action: :create, controller: :oneclick_inscriptions) do |f| %>
4 | <%= f.text_field :email %>
5 | <%= f.text_field :username %>
6 | <%= f.submit 'Inscribe' %>
7 | <% end %>
8 |
--------------------------------------------------------------------------------
/lib/webpay_rails/responses/reverse.rb:
--------------------------------------------------------------------------------
1 | module WebpayRails::Responses
2 | class Reverse < WebpayRails::Response
3 | def self.attr_list
4 | [:return]
5 | end
6 |
7 | attr_accessor(*attr_list)
8 |
9 | def success?
10 | self.return == 'true'
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/spec/internal/app/models/concerns/universally_unique_identifiable.rb:
--------------------------------------------------------------------------------
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 | end
12 |
--------------------------------------------------------------------------------
/lib/webpay_rails/responses/remove_user.rb:
--------------------------------------------------------------------------------
1 | module WebpayRails::Responses
2 | class RemoveUser < WebpayRails::Response
3 | def self.attr_list
4 | [:return]
5 | end
6 |
7 | attr_accessor(*attr_list)
8 |
9 | def success?
10 | self.return == 'true'
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | begin
2 | require 'bundler/setup'
3 | rescue LoadError
4 | puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5 | end
6 |
7 | require "rspec/core/rake_task"
8 |
9 | desc "Run all examples"
10 | RSpec::Core::RakeTask.new(:spec) do |t|
11 | t.rspec_opts = %w[--color]
12 | end
13 |
14 | task default: :spec
15 |
--------------------------------------------------------------------------------
/lib/webpay_rails/responses/init_transaction.rb:
--------------------------------------------------------------------------------
1 | module WebpayRails
2 | module Responses
3 | class InitTransaction < WebpayRails::Response
4 | def self.attr_list
5 | [:token, :url]
6 | end
7 |
8 | attr_accessor(*attr_list)
9 |
10 | def success?
11 | !token.blank?
12 | end
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/spec/internal/app/views/normal_orders/gateway.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_tag(@url, method: @method, style: 'display: none;', id: 'gatewayForm', enforce_utf8: false, authenticity_token: false) do %>
2 | <%= hidden_field_tag(:token_ws, @token) %>
3 | <%= submit_tag("Continuar a webpay") %>
4 | <% end %>
5 |
6 |
9 |
--------------------------------------------------------------------------------
/spec/internal/app/views/oneclick_inscriptions/gateway.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_tag(@url, method: @method, style: 'display: none;', id: 'gatewayForm', enforce_utf8: false, authenticity_token: false) do %>
2 | <%= hidden_field_tag(:TBK_TOKEN, @token) %>
3 | <%= submit_tag("Continuar a webpay") %>
4 | <% end %>
5 |
6 |
9 |
--------------------------------------------------------------------------------
/lib/webpay_rails/responses/transaction_nullify.rb:
--------------------------------------------------------------------------------
1 | module WebpayRails::Responses
2 | class TransactionNullify < WebpayRails::Response
3 | def self.attr_list
4 | [:token, :authorization_code, :authorization_date, :balance,
5 | :nullified_amount]
6 | end
7 |
8 | attr_accessor(*attr_list)
9 |
10 | def success?
11 | !token.blank?
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/lib/webpay_rails/responses/finish_inscription.rb:
--------------------------------------------------------------------------------
1 | module WebpayRails::Responses
2 | class FinishInscription < WebpayRails::Response
3 | def self.attr_list
4 | [:response_code, :auth_code, :tbk_user, :last_4_card_digits,
5 | :credit_card_type]
6 | end
7 |
8 | attr_accessor(*attr_list)
9 |
10 | def success?
11 | response_code.to_i.zero?
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/spec/internal/app/models/concerns/orderable.rb:
--------------------------------------------------------------------------------
1 | module Orderable
2 | extend ActiveSupport::Concern
3 |
4 | included do
5 | enum status: [:created, :approved, :failed, :canceled, :expired, :pending,
6 | :refunded]
7 |
8 | scope :approved, -> { where(status: self.statuses[:approved]) }
9 | scope :normal_selling, -> { where(tbk_payment_type_code: 'VN') }
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/lib/webpay_rails/responses/authorization.rb:
--------------------------------------------------------------------------------
1 | module WebpayRails::Responses
2 | class Authorization < WebpayRails::Response
3 | def self.attr_list
4 | [:response_code, :authorization_code, :transaction_id,
5 | :last_4_card_digits, :credit_card_type]
6 | end
7 |
8 | attr_accessor(*attr_list)
9 |
10 | def success?
11 | response_code.to_i.zero?
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/spec/internal/app/views/oneclick_inscriptions/success.html.erb:
--------------------------------------------------------------------------------
1 | Success inscription
2 |
3 | response_code: <%= @response.response_code %>
4 | auth_code: <%= @response.auth_code %>
5 | tbk_user: <%= @response.tbk_user %>
6 | last_4_card_digits: <%= @response.last_4_card_digits %>
7 | credit_card_type: <%= @response.credit_card_type %>
8 |
--------------------------------------------------------------------------------
/lib/webpay_rails/response.rb:
--------------------------------------------------------------------------------
1 | module WebpayRails
2 | class Response
3 | def self.attr_list
4 | []
5 | end
6 |
7 | def initialize(response)
8 | document = Nokogiri::HTML(response.to_s)
9 | self.class.attr_list.each do |k|
10 | v = document.at_xpath("//#{k.to_s.tr('_', '')}")
11 | send("#{k}=", v.text.to_s) unless v.nil?
12 | end
13 | end
14 |
15 | attr_accessor(*attr_list)
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/spec/internal/config/routes.rb:
--------------------------------------------------------------------------------
1 | Rails.application.routes.draw do
2 | root to: 'normal_orders#new'
3 |
4 | resources :normal_orders, only: [:new, :create] do
5 | member do
6 | post :return
7 | post :final
8 | end
9 | end
10 |
11 | resources :oneclick_inscriptions, only: [:new, :create] do
12 | collection do
13 | post :finish
14 | end
15 | end
16 |
17 | resources :oneclick_orders, only: [:new, :create]
18 | end
19 |
--------------------------------------------------------------------------------
/spec/internal/app/views/oneclick_orders/success.html.erb:
--------------------------------------------------------------------------------
1 | Success transaction
2 |
3 | tbk_response_code: <%= @response.response_code %>
4 | tbk_authorization_code: <%= @response.authorization_code %>
5 | tbk_transaction_id: <%= @response.transaction_id %>
6 | tbk_last_4_card_digits: <%= @response.last_4_card_digits %>
7 | tbk_credit_card_type: <%= @response.credit_card_type %>
8 |
--------------------------------------------------------------------------------
/spec/internal/app/models/order/normal_invalid.rb:
--------------------------------------------------------------------------------
1 | class Order::NormalInvalid < ActiveRecord::Base
2 | extend WebpayRails
3 | include Orderable
4 | include UniversallyUniqueIdentifiable
5 |
6 | self.table_name = 'orders'
7 |
8 | webpay_rails(
9 | commerce_code: 597020000541,
10 | private_key: Rails.root.join('vendor/vault/597020000541.key').to_s,
11 | public_cert: Rails.root.join('vendor/vault/597020000541.crt').to_s,
12 | webpay_cert: Rails.root.join('vendor/vault/597020000541.crt').to_s
13 | )
14 | end
15 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: ruby
2 | cache: bundler
3 | sudo: required
4 | dist: trusty
5 | before_install:
6 | - sudo apt-get update
7 | - sudo apt-get install chromium-chromedriver
8 | before_script:
9 | - "export PATH=$PATH:/usr/lib/chromium-browser/"
10 | - "export DISPLAY=:99.0"
11 | - "sh -e /etc/init.d/xvfb start"
12 | - sleep 3 # give xvfb some time to start
13 | rvm:
14 | - 2.2.2
15 | - 2.3.0
16 | env:
17 | - CAPYBARA_DRIVER=headless_chrome
18 | after_success:
19 | - coveralls
20 | notifications:
21 | email: false
22 |
--------------------------------------------------------------------------------
/spec/internal/app/models/order/normal.rb:
--------------------------------------------------------------------------------
1 | class Order::Normal < ActiveRecord::Base
2 | extend WebpayRails
3 | include Orderable
4 | include UniversallyUniqueIdentifiable
5 |
6 | self.table_name = 'orders'
7 |
8 | webpay_rails(
9 | commerce_code: 597020000541,
10 | private_key: Rails.root.join('vendor/vault/597020000541.key').to_s,
11 | public_cert: Rails.root.join('vendor/vault/597020000541.crt').to_s,
12 | webpay_cert: Rails.root.join('vendor/vault/tbk.pem').to_s
13 | )
14 |
15 | def buy_order_for_transbank_normal
16 | uuid.first(30).delete!('-')
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | # Declare your gem's dependencies in secret_id.gemspec.
4 | # Bundler will treat runtime dependencies like base dependencies, and
5 | # development dependencies will be added by default to the :development group.
6 | gemspec
7 |
8 | # Declare any dependencies that are still in development here instead of in
9 | # your gemspec. These might include edge Rails or gems from your path or
10 | # Git. Remember to move these dependencies to your gemspec before releasing
11 | # your gem to rubygems.org.
12 |
13 | # To use a debugger
14 | # gem 'byebug', group: [:development, :test]
15 |
--------------------------------------------------------------------------------
/lib/webpay_rails/responses/transaction_result.rb:
--------------------------------------------------------------------------------
1 | module WebpayRails::Responses
2 | class TransactionResult < WebpayRails::Response
3 | def self.attr_list
4 | [
5 | :buy_order, :session_id, :accounting_date, :transaction_date, :vci,
6 | :url_redirection,
7 |
8 | # card details
9 | :card_number, :card_expiration_date,
10 |
11 | # transaction details
12 | :authorization_code, :payment_type_code, :response_code,
13 | :amount, :shares_number, :commerce_code
14 | ]
15 | end
16 |
17 | attr_accessor(*attr_list)
18 |
19 | def approved?
20 | response_code.to_i.zero?
21 | end
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/spec/internal/db/schema.rb:
--------------------------------------------------------------------------------
1 | ActiveRecord::Schema.define do
2 | create_table(:orders, force: true) do |t|
3 | t.string :uuid
4 | t.string :tbk_token_ws, index: true
5 | t.string :tbk_accounting_date
6 | t.string :tbk_buy_order
7 | t.string :tbk_card_number
8 | t.string :tbk_commerce_code
9 | t.string :tbk_authorization_code
10 | t.string :tbk_payment_type_code
11 | t.string :tbk_response_code
12 | t.string :tbk_transaction_date
13 | t.string :tbk_vci
14 | t.string :tbk_session_id
15 | t.string :tbk_card_expiration_date
16 | t.string :tbk_shares_number
17 |
18 | t.string :tbk_transaction_id
19 | t.string :tbk_credit_card_type
20 |
21 | t.integer :amount
22 | t.integer :status, default: 0
23 |
24 | t.timestamps
25 | end
26 |
27 | create_table(:users, force: true) do |t|
28 | t.string :username
29 | t.string :email
30 | t.string :tbk_user
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/lib/webpay_rails/soap_nullify.rb:
--------------------------------------------------------------------------------
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
33 |
--------------------------------------------------------------------------------
/lib/webpay_rails/vault.rb:
--------------------------------------------------------------------------------
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
37 |
--------------------------------------------------------------------------------
/spec/internal/app/models/order/oneclick.rb:
--------------------------------------------------------------------------------
1 | class Order::Oneclick < ActiveRecord::Base
2 | extend WebpayRails
3 | include Orderable
4 | include UniversallyUniqueIdentifiable
5 |
6 | self.table_name = 'orders'
7 |
8 | webpay_rails(
9 | commerce_code: 597020000547,
10 | private_key: Rails.root.join('vendor/vault/597020000547.key').to_s,
11 | public_cert: Rails.root.join('vendor/vault/597020000547.crt').to_s,
12 | webpay_cert: Rails.root.join('vendor/vault/tbk.pem').to_s
13 | )
14 |
15 | scope :created_on, ->(at) { where(created_at: at) }
16 |
17 | # Identificador único de la compra generado por el comercio.
18 | # Debe ser timestamp [yyyymmddhhMMss] + un correlativo de tres dígitos.
19 | # Ej: Para la tercera transacción realizada el día 15 de julio de 2011 a las
20 | # 11:55:50 la orden de compra sería: 20110715115550003.
21 | def buy_order_for_transbank_oneclick
22 | order = Order::Oneclick.created_on(created_at).first!
23 | time = created_at.strftime("%Y%m%d%H%M%S")
24 | offset = (id - order.id + 1).to_s.rjust(3, '0')
25 | time + offset
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/MIT-LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2016 Sebastián Orellana
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/spec/internal/vendor/vault/tbk.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDKTCCAhECBFZl7uIwDQYJKoZIhvcNAQEFBQAwWTELMAkGA1UEBhMCQ0wxDjAMBgNVBAgMBUNo
3 | aWxlMREwDwYDVQQHDAhTYW50aWFnbzEMMAoGA1UECgwDa2R1MQwwCgYDVQQLDANrZHUxCzAJBgNV
4 | BAMMAjEwMB4XDTE1MTIwNzIwNDEwNloXDTE4MDkwMjIwNDEwNlowWTELMAkGA1UEBhMCQ0wxDjAM
5 | BgNVBAgMBUNoaWxlMREwDwYDVQQHDAhTYW50aWFnbzEMMAoGA1UECgwDa2R1MQwwCgYDVQQLDANr
6 | ZHUxCzAJBgNVBAMMAjEwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAizJUWTDC7nfP
7 | 3jmZpWXFdG9oKyBrU0Bdl6fKif9a1GrwevThsU5Dq3wiRfYvomStNjFDYFXOs9pRIxqX2AWDybjA
8 | X/+bdDTVbM+xXllA9stJY8s7hxAvwwO7IEuOmYDpmLKP7J+4KkNH7yxsKZyLL9trG3iSjV6Y6SO5
9 | EEhUsdxoJFAow/h7qizJW0kOaWRcljf7kpqJAL3AadIuqV+hlf+Ts/64aMsfSJJA6xdbdp9ddgVF
10 | oqUl1M8vpmd4glxlSrYmEkbYwdI9uF2d6bAeaneBPJFZr6KQqlbbrVyeJZqmMlEPy0qPco1TIxrd
11 | EHlXgIFJLyyMRAyjX9i4l70xjwIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQBn3tUPS6e2USgMrPKp
12 | sxU4OTfW64+mfD6QrVeBOh81f6aGHa67sMJn8FE/cG6jrUmX/FP1/Cpbpvkm5UUlFKpgaFfHv+Kg
13 | CpEvgcRIv/OeIi6Jbuu3NrPdGPwzYkzlOQnmgio5RGb6GSs+OQ0mUWZ9J1+YtdZc+xTga0x7nsCT
14 | 5xNcUXsZKhyjoKhXtxJm3eyB3ysLNyuL/RHy/EyNEWiUhvt1SIePnW+Y4/cjQWYwNqSqMzTSW9TP
15 | 2QR2bX/W2H6ktRcLsgBK9mq7lE36p3q6c9DtZJE+xfA4NGCYWM9hd8pbusnoNO7AFxJZOuuvLZI7
16 | JvD7YLhPvCYKry7N6x3l
17 | -----END CERTIFICATE-----
18 |
--------------------------------------------------------------------------------
/lib/webpay_rails.rb:
--------------------------------------------------------------------------------
1 | require 'rails'
2 | require 'active_support/concern'
3 |
4 | require 'signer'
5 | require 'savon'
6 | require 'nokogiri'
7 | require 'base64'
8 | require 'digest/sha1'
9 | require 'openssl'
10 |
11 | require 'webpay_rails/version'
12 | require 'webpay_rails/errors'
13 | require 'webpay_rails/vault'
14 | require 'webpay_rails/soap'
15 | require 'webpay_rails/soap_normal'
16 | require 'webpay_rails/soap_nullify'
17 | require 'webpay_rails/soap_oneclick'
18 | require 'webpay_rails/verifier'
19 | require 'webpay_rails/response'
20 | require 'webpay_rails/responses/init_transaction'
21 | require 'webpay_rails/responses/transaction_result'
22 | require 'webpay_rails/responses/transaction_nullify'
23 | require 'webpay_rails/responses/init_inscription'
24 | require 'webpay_rails/responses/finish_inscription'
25 | require 'webpay_rails/responses/authorization'
26 | require 'webpay_rails/responses/reverse'
27 | require 'webpay_rails/responses/remove_user'
28 | require 'webpay_rails/railites'
29 |
30 | module WebpayRails
31 | autoload :Base, 'webpay_rails/base'
32 |
33 | class << self
34 | attr_accessor :rails_logger
35 | end
36 |
37 | def self.extended(base)
38 | base.include WebpayRails::Base
39 |
40 | super
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/spec/internal/app/views/normal_orders/success.html.erb:
--------------------------------------------------------------------------------
1 | Success transaction
2 |
3 | id: <%= @order.id %>
4 | tbk_token_ws: <%= @order.tbk_token_ws %>
5 | tbk_accounting_date: <%= @order.tbk_accounting_date %>
6 | tbk_buy_order: <%= @order.tbk_buy_order %>
7 | tbk_card_number: <%= @order.tbk_card_number %>
8 | tbk_commerce_code: <%= @order.tbk_commerce_code %>
9 | tbk_authorization_code: <%= @order.tbk_authorization_code %>
10 | tbk_payment_type_code: <%= @order.tbk_payment_type_code %>
11 | tbk_response_code: <%= @order.tbk_response_code %>
12 | tbk_transaction_date: <%= @order.tbk_transaction_date %>
13 | tbk_vci: <%= @order.tbk_vci %>
14 | tbk_session_id: <%= @order.tbk_session_id %>
15 | tbk_card_expiration_date: <%= @order.tbk_card_expiration_date %>
16 | tbk_shares_number: <%= @order.tbk_shares_number %>
17 | amount: <%= @order.amount %>
18 | status: <%= @order.status %>
19 |
--------------------------------------------------------------------------------
/spec/internal/app/controllers/oneclick_inscriptions_controller.rb:
--------------------------------------------------------------------------------
1 | class OneclickInscriptionsController < ActionController::Base
2 | def new
3 | @user = User.new
4 | end
5 |
6 | def create
7 | @user = User.create(user_params)
8 | @response = Order::Oneclick.init_inscription(init_inscription_params)
9 |
10 | @method = :post
11 | @url = @response.url_webpay
12 | @token = @response.token
13 |
14 | render :gateway
15 | rescue WebpayRails::SoapError
16 | render :failed
17 | end
18 |
19 | def finish
20 | @user = User.find(params[:user_id])
21 | @response = Order::Oneclick.finish_inscription(finish_inscription_params)
22 | if @response.success?
23 | @user.update(tbk_user: @response.tbk_user)
24 | render :success
25 | else
26 | render :failed
27 | end
28 | rescue WebpayRails::SoapError
29 | render :failed
30 | end
31 |
32 | private
33 |
34 | def user_params
35 | params.require(:user).permit(:username, :email)
36 | end
37 |
38 | def init_inscription_params
39 | user_params.merge(return_url: url_for(action: :finish, user_id: @user.id))
40 | end
41 |
42 | def finish_inscription_params
43 | {
44 | token: params[:TBK_TOKEN]
45 | }
46 | end
47 | end
48 |
--------------------------------------------------------------------------------
/spec/webpay_rails_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 | require 'vault_helper'
3 |
4 | describe WebpayRails do
5 | before(:all) { @webpay_rails_params = { commerce_code: COMMERCE_CODE,
6 | private_key: PRIVATE_KEY,
7 | webpay_cert: WEBPAY_CERT,
8 | public_cert: PUBLIC_CERT } }
9 |
10 | describe WebpayRails::Base do
11 | it { expect{ Order::Blank.webpay_rails(@webpay_rails_params.except(:commerce_code)) }.to raise_error(WebpayRails::MissingCommerceCode) }
12 | it { expect{ Order::Blank.webpay_rails(@webpay_rails_params.except(:private_key)) }.to raise_error(WebpayRails::MissingPrivateKey) }
13 | it { expect{ Order::Blank.webpay_rails(@webpay_rails_params.except(:webpay_cert)) }.to raise_error(WebpayRails::MissingWebpayCertificate) }
14 | it { expect{ Order::Blank.webpay_rails(@webpay_rails_params.except(:public_cert)) }.to raise_error(WebpayRails::MissingPublicCertificate) }
15 | it { expect{ Order::Blank.webpay_rails(@webpay_rails_params.merge(private_key: '', public_cert: '', webpay_cert: '')) }.to raise_error(WebpayRails::FileNotFound) }
16 | it { expect{ Order::Blank.webpay_rails(@webpay_rails_params.merge(environment: :other)) }.to raise_error(WebpayRails::InvalidEnvironment) }
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | require 'bundler'
2 |
3 | Bundler.require :default, :development
4 |
5 | require 'capybara/rspec'
6 |
7 | Combustion.initialize! :active_record, :action_controller, :action_view
8 |
9 | require 'rspec/rails'
10 | require 'capybara/rails'
11 |
12 | Capybara.register_driver :chrome do |app|
13 | capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(
14 | chromeOptions: { args: %w[window-size=1024,768] }
15 | )
16 |
17 | Capybara::Selenium::Driver.new app, browser: :chrome,
18 | desired_capabilities: capabilities
19 | end
20 |
21 | Capybara.register_driver :headless_chrome do |app|
22 | capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(
23 | chromeOptions: { args: %w[headless disable-gpu window-size=1024,768] }
24 | )
25 |
26 | Capybara::Selenium::Driver.new app, browser: :chrome,
27 | desired_capabilities: capabilities
28 | end
29 |
30 | driver_name = (ENV['CAPYBARA_DRIVER'] || 'headless_chrome').to_sym
31 | Capybara.javascript_driver = driver_name
32 | Capybara.default_driver = driver_name
33 | Capybara.default_max_wait_time = 10
34 |
35 | require 'coveralls'
36 |
37 | Coveralls.wear!
38 |
39 | require 'webpay_rails'
40 |
41 | RSpec.configure do |config|
42 | config.use_transactional_fixtures = true
43 | end
44 |
--------------------------------------------------------------------------------
/spec/internal/vendor/vault/597020000541.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDujCCAqICCQCZ42cY33KRTzANBgkqhkiG9w0BAQsFADCBnjELMAkGA1UEBhMC
3 | Q0wxETAPBgNVBAgMCFNhbnRpYWdvMRIwEAYDVQQKDAlUcmFuc2JhbmsxETAPBgNV
4 | BAcMCFNhbnRpYWdvMRUwEwYDVQQDDAw1OTcwMjAwMDA1NDExFzAVBgNVBAsMDkNh
5 | bmFsZXNSZW1vdG9zMSUwIwYJKoZIhvcNAQkBFhZpbnRlZ3JhZG9yZXNAdmFyaW9z
6 | LmNsMB4XDTE2MDYyMjIxMDkyN1oXDTI0MDYyMDIxMDkyN1owgZ4xCzAJBgNVBAYT
7 | AkNMMREwDwYDVQQIDAhTYW50aWFnbzESMBAGA1UECgwJVHJhbnNiYW5rMREwDwYD
8 | VQQHDAhTYW50aWFnbzEVMBMGA1UEAwwMNTk3MDIwMDAwNTQxMRcwFQYDVQQLDA5D
9 | YW5hbGVzUmVtb3RvczElMCMGCSqGSIb3DQEJARYWaW50ZWdyYWRvcmVzQHZhcmlv
10 | cy5jbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANApVXB/EQtbviqQ
11 | j1J82EiHJslyPO0RLAZEM2gNUCXuMPwe4OirylfQ2qn5zYTL3ff8qZhn9EQ0D4ZQ
12 | Wxpc8pis9cYdJUAQ/vTGa4PCbvP3dZNKSG9UC0A54UYEdk9eJ4F6T+DyECrauw7H
13 | RwcmxVOb7wClanR7yJmRc6nsW2Y11scYU/v7BnA+FbOu933Ogfl49lKyhe0MleaT
14 | A6tBwgi0zJmn1gJjax8peopkDPm6gtdoJxBABJKyYkjuj/9tZvYgybOSkGp6SW8t
15 | GhlvJqHGERwzB2Y7U4iD9PiQCYC/SrB/q13ZNm0+2nq3u08ziv2xMIZGBF5zDLf+
16 | ub1egH8CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAdgNpIS2NZFx5PoYwJZf8faze
17 | NmKQg73seDGuP8d8w/CZf1Py/gsJFNbh4CEySWZRCzlOKxzmtPTmyPdyhObjMA8E
18 | Adps9DtgiN2ITSF1HUFmhMjI5V7U2L9LyEdpUaieYyPBfxiicdWz2YULVuOYDJHR
19 | n05jlj/EjYa5bLKs/yggYiqMkZdIX8NiLL6ZTERIvBa6azDKs6yDsCsnE1M5tzQI
20 | VVEkZtEfil6E1tz8v3yLZapLt+8jmPq1RCSx3Zh4fUkxBTpUW/9SWUNEXbKK7bB3
21 | zfB3kGE55K5nxHKfQlrqdHLcIo+vdShATwYnmhUkGxUnM9qoCDlB8lYu3rFi9w==
22 | -----END CERTIFICATE-----
23 |
--------------------------------------------------------------------------------
/spec/internal/vendor/vault/597020000547.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDujCCAqICCQCFNCTEl24W2TANBgkqhkiG9w0BAQsFADCBnjELMAkGA1UEBhMC
3 | Q0wxETAPBgNVBAgMCFNhbnRpYWdvMRIwEAYDVQQKDAlUcmFuc2JhbmsxETAPBgNV
4 | BAcMCFNhbnRpYWdvMRUwEwYDVQQDDAw1OTcwMjAwMDA1NDcxFzAVBgNVBAsMDkNh
5 | bmFsZXNSZW1vdG9zMSUwIwYJKoZIhvcNAQkBFhZpbnRlZ3JhZG9yZXNAdmFyaW9z
6 | LmNsMB4XDTE2MDYyMzE2MzcxM1oXDTI0MDYyMTE2MzcxM1owgZ4xCzAJBgNVBAYT
7 | AkNMMREwDwYDVQQIDAhTYW50aWFnbzESMBAGA1UECgwJVHJhbnNiYW5rMREwDwYD
8 | VQQHDAhTYW50aWFnbzEVMBMGA1UEAwwMNTk3MDIwMDAwNTQ3MRcwFQYDVQQLDA5D
9 | YW5hbGVzUmVtb3RvczElMCMGCSqGSIb3DQEJARYWaW50ZWdyYWRvcmVzQHZhcmlv
10 | cy5jbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAORastwv3YYHVbBp
11 | L+aeRi73fTsXjr/qaCuNc08SFFzi6RujRFvh2+UM9K05NUxFSVAklW9G1fJ37A9K
12 | B6JQ/+yFP877xFifMyOXGu1Wdrmduy7nngGrM0X0RlpCfE6kQfKhP0LhyFFSRIGP
13 | WMaRJg9uYRCJWVPeBUUUXB0qSdfvKNyvQ0qpG3vWlhhr7Pocc65U4TuPBwFMC9Bd
14 | qMjKsrEkIUamX33kmTKeKrCpRO4iK+aZPN+90Ki6328Jtn3OevkRtIFUOO0ik36T
15 | 8dkVTPZ2ydwKGLaaBHOB0WlJ1QieWIhmMuvQrFDST7I/WUy9Wr0ySul58oKFT6Jf
16 | Xe19dysCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAubHNHDzyMLXuNQwawdhrzJYf
17 | Cvi2NsAqVBKICp+VC94OqVsdWknrqm8+Wz+1DZV1ezTvoVgagiC/ZrfHvn9DEP45
18 | 7JttrOt2Sbr+F2Pj3oBl1RiQ2QkIXBRaSmipKaQB/cWRd0ZiO7uT5mP7eQtO5qFJ
19 | 4WST6dXtks2Oz4G7eMpqnctOfFiGBi1i6omD7LZg+qpbeTFWTEgZFcAUTrViRLl2
20 | PEhUMVAobvvY7zUmzeu2mAMlWVNoaJysl6sH7Gii3T/xbxHsbxV8bZgvgQwiwFVP
21 | +ffp06jqVndIhoeiTOz0MXgPIXIESaDraY2dgNTgEs2GwLNjy2cMB5pkjkAZ4g==
22 | -----END CERTIFICATE-----
23 |
--------------------------------------------------------------------------------
/spec/nullify_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 | require 'vault_helper'
3 |
4 | describe WebpayRails::Responses::TransactionNullify do
5 | before(:all) { @approved_order = Order::Normal.normal_selling.approved.first! }
6 | before(:all) do
7 | @nullify_params =
8 | {
9 | authorization_code: @approved_order.tbk_authorization_code,
10 | authorized_amount: @approved_order.amount,
11 | buy_order: @approved_order.tbk_buy_order,
12 | nullify_amount: @approved_order.amount
13 | }
14 | end
15 |
16 | context 'when all is ok' do
17 | before(:all) { @nullified_transaction = Order::Normal.nullify(@nullify_params) }
18 |
19 | it { expect(@nullified_transaction).to be_kind_of(WebpayRails::Responses::TransactionNullify) }
20 |
21 | describe '.token' do
22 | it { expect(@nullified_transaction.token).not_to be_blank }
23 | end
24 |
25 | describe '.authorization_code' do
26 | it { expect(@nullified_transaction.authorization_code).not_to be_blank }
27 | end
28 |
29 | describe '.authorization_date' do
30 | it { expect(@nullified_transaction.authorization_date).not_to be_blank }
31 | end
32 |
33 | describe '.balance' do
34 | it { expect(@nullified_transaction.balance).not_to be_blank }
35 | end
36 |
37 | describe '.nullified_amount' do
38 | it { expect(@nullified_transaction.nullified_amount).not_to be_blank }
39 | end
40 | end
41 |
42 | context 'when not' do
43 | it { expect { Order::Normal.nullify(@nullify_params.merge(nullify_amount: 0)) }.to raise_error(WebpayRails::RequestFailed) }
44 | pending 'should raise WebpayRails::InvalidCertificate'
45 | end
46 | end
47 |
--------------------------------------------------------------------------------
/webpay_rails.gemspec:
--------------------------------------------------------------------------------
1 | # -*- encoding: utf-8 -*-
2 | $:.push File.expand_path('../lib', __FILE__)
3 |
4 | require 'webpay_rails/version'
5 |
6 | Gem::Specification.new do |s|
7 | s.platform = Gem::Platform::RUBY
8 | s.name = 'webpay_rails'
9 | s.version = WebpayRails::VERSION
10 | s.summary = 'WebpayRails is an easy solution for integrate Transbank Webpay in Rails applications.'
11 | s.description = s.summary
12 | s.authors = ['Sebastián Orellana']
13 | s.email = ['limcross@gmail.com']
14 | s.homepage = 'https://github.com/limcross/webpay_rails'
15 | s.license = 'MIT'
16 | s.require_paths = ['lib']
17 | s.files = `git ls-files`.split("\n")
18 | s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19 |
20 | s.required_ruby_version = '>= 2.2.2'
21 |
22 | s.add_dependency 'signer', '~> 1.4.3'
23 | s.add_dependency 'savon', '~> 2'
24 | s.add_dependency 'nokogiri', '~> 1.6', '>= 1.6.7.2'
25 | s.add_dependency 'activesupport', '>= 4', '< 5.1'
26 | s.add_dependency 'railties', '>= 4.1.0', '< 5.1'
27 |
28 | s.add_development_dependency 'rspec', '~> 3.5'
29 | s.add_development_dependency 'rspec-rails', '~> 3.5'
30 | s.add_development_dependency 'capybara', '~> 2.10', '>= 2.10.1'
31 | s.add_development_dependency 'selenium-webdriver', '~> 3.0'
32 | s.add_development_dependency 'combustion', '~> 0.5.5'
33 | s.add_development_dependency 'activerecord', '~> 5.0', '>= 5.0.0.1'
34 | s.add_development_dependency 'actionpack', '~> 5.0', '>= 5.0.0.1'
35 | s.add_development_dependency 'sqlite3'
36 | s.add_development_dependency 'rake'
37 | s.add_development_dependency 'coveralls'
38 | end
39 |
--------------------------------------------------------------------------------
/spec/internal/app/controllers/oneclick_orders_controller.rb:
--------------------------------------------------------------------------------
1 | class OneclickOrdersController < ActionController::Base
2 | def new
3 | @order = Order::Oneclick.new
4 | end
5 |
6 | def create
7 | @user = User.first!
8 | @order = Order::Oneclick.create!(create_params)
9 | @response = Order::Oneclick.authorize(authorize_params)
10 | if @response.success?
11 | @order.update!(update_params.merge(status: :approved))
12 | render :success
13 | else
14 | render :failed
15 | end
16 | rescue WebpayRails::SoapError
17 | render :failed
18 | end
19 |
20 | private
21 |
22 | def create_params
23 | params.require(:order_oneclick).permit(:amount)
24 | end
25 |
26 | def authorize_params
27 | {
28 | buy_order: @order.buy_order_for_transbank_oneclick,
29 | tbk_user: @user.tbk_user,
30 | username: @user.username,
31 | amount: @order.amount
32 | }
33 | end
34 |
35 | def update_params
36 | {
37 | #tbk_token_ws: '',
38 | #tbk_accounting_date: '',
39 | tbk_buy_order: @order.buy_order_for_transbank_oneclick,
40 | tbk_card_number: @response.last_4_card_digits,
41 | #tbk_commerce_code: '',
42 | tbk_authorization_code: @response.authorization_code,
43 | tbk_payment_type_code: 'VN',
44 | tbk_response_code: @response.response_code,
45 | #tbk_transaction_date: '',
46 | #tbk_vci: '',
47 | #tbk_session_id: '',
48 | #tbk_card_expiration_date: '',
49 | tbk_shares_number: 0,
50 | amount: @order.amount,
51 |
52 | tbk_transaction_id: @response.transaction_id,
53 | tbk_credit_card_type: @response.credit_card_type
54 | }
55 | end
56 | end
57 |
--------------------------------------------------------------------------------
/lib/webpay_rails/soap_normal.rb:
--------------------------------------------------------------------------------
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
53 |
--------------------------------------------------------------------------------
/spec/internal/vendor/vault/597020000541.key:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIIEpQIBAAKCAQEA0ClVcH8RC1u+KpCPUnzYSIcmyXI87REsBkQzaA1QJe4w/B7g
3 | 6KvKV9DaqfnNhMvd9/ypmGf0RDQPhlBbGlzymKz1xh0lQBD+9MZrg8Ju8/d1k0pI
4 | b1QLQDnhRgR2T14ngXpP4PIQKtq7DsdHBybFU5vvAKVqdHvImZFzqexbZjXWxxhT
5 | +/sGcD4Vs673fc6B+Xj2UrKF7QyV5pMDq0HCCLTMmafWAmNrHyl6imQM+bqC12gn
6 | EEAEkrJiSO6P/21m9iDJs5KQanpJby0aGW8mocYRHDMHZjtTiIP0+JAJgL9KsH+r
7 | Xdk2bT7aere7TzOK/bEwhkYEXnMMt/65vV6AfwIDAQABAoIBAHnIlOn6DTi99eXl
8 | KVSzIb5dA747jZWMxFruL70ifM+UKSh30FGPoBP8ZtGnCiw1ManSMk6uEuSMKMEF
9 | 5iboVi4okqnTh2WSC/ec1m4BpPQqxKjlfrdTTjnHIxrZpXYNucMwkeci93569ZFR
10 | 2SY/8pZV1mBkZoG7ocLmq+qwE1EaBEL/sXMvuF/h08nJ71I4zcclpB8kN0yFrBCW
11 | 7scqOwTLiob2mmU2bFHOyyjTkGOlEsBQxhtVwVEt/0AFH/ucmMTP0vrKOA0HkhxM
12 | oeR4k2z0qwTzZKXuEZtsau8a/9B3S3YcgoSOhRP/VdY1WL5hWDHeK8q1Nfq2eETX
13 | jnQ4zjECgYEA7z2/biWe9nDyYDZM7SfHy1xF5Q3ocmv14NhTbt8iDlz2LsZ2JcPn
14 | EMV++m88F3PYdFUOp4Zuw+eLJSrBqfuPYrTVNH0v/HdTqTS70R2YZCFb9g0ryaHV
15 | TRwYovu/oQMV4LBSzrwdtCrcfUZDtqMYmmZfEkdjCWCEpEi36nlG0JMCgYEA3r49
16 | o+soFIpDqLMei1tF+Ah/rm8oY5f4Wc82kmSgoPFCWnQEIW36i/GRaoQYsBp4loue
17 | vyPuW+BzoZpVcJDuBmHY3UOLKr4ZldOn2KIj6sCQZ1mNKo5WuZ4YFeL5uyp9Hvio
18 | TCPGeXghG0uIk4emSwolJVSbKSRi6SPsiANff+UCgYEAvNMRmlAbLQtsYb+565xw
19 | NvO3PthBVL4dLL/Q6js21/tLWxPNAHWklDosxGCzHxeSCg9wJ40VM4425rjebdld
20 | DF0Jwgnkq/FKmMxESQKA2tbxjDxNCTGv9tJsJ4dnch/LTrIcSYt0LlV9/WpN24LS
21 | 0lpmQzkQ07/YMQosDuZ1m/0CgYEAu9oHlEHTmJcO/qypmu/ML6XDQPKARpY5Hkzy
22 | gj4ZdgJianSjsynUfsepUwK663I3twdjR2JfON8vxd+qJPgltf45bknziYWvgDtz
23 | t/Duh6IFZxQQSQ6oN30MZRD6eo4X3dHp5eTaE0Fr8mAefAWQCoMw1q3m+ai1PlhM
24 | uFzX4r0CgYEArx4TAq+Z4crVCdABBzAZ7GvvAXdxvBo0AhD9IddSWVTCza972wta
25 | 5J2rrS/ye9Tfu5j2IbTHaLDz14mwMXr1S4L39UX/NifLc93KHie/yjycCuu4uqNo
26 | MtdweTnQt73lN2cnYedRUhw9UTfPzYu7jdXCUAyAD4IEjFQrswk2x04=
27 | -----END RSA PRIVATE KEY-----
28 |
--------------------------------------------------------------------------------
/spec/internal/vendor/vault/597020000547.key:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIIEpAIBAAKCAQEA5Fqy3C/dhgdVsGkv5p5GLvd9OxeOv+poK41zTxIUXOLpG6NE
3 | W+Hb5Qz0rTk1TEVJUCSVb0bV8nfsD0oHolD/7IU/zvvEWJ8zI5ca7VZ2uZ27Luee
4 | AaszRfRGWkJ8TqRB8qE/QuHIUVJEgY9YxpEmD25hEIlZU94FRRRcHSpJ1+8o3K9D
5 | Sqkbe9aWGGvs+hxzrlThO48HAUwL0F2oyMqysSQhRqZffeSZMp4qsKlE7iIr5pk8
6 | 373QqLrfbwm2fc56+RG0gVQ47SKTfpPx2RVM9nbJ3AoYtpoEc4HRaUnVCJ5YiGYy
7 | 69CsUNJPsj9ZTL1avTJK6XnygoVPol9d7X13KwIDAQABAoIBAQDPB6/rUvYbIqE8
8 | nFESW+KziCwgm/4O3x1shwTI5lJR2GORbBd42i973aAjQJ+is5qBL3nP9j/YYYNC
9 | ZVLAhYFR1YkBRl9AHa3GkaOXE/H13RwsrU8ioi2NOadjA64humgT6r8pCvyLRfPY
10 | JrdM56HDEcassGmtULgkZg4RXxqtym6dcpPmuXtCHFZ7JEWVSKWH+STReAh7unwD
11 | TYOZlsnU5FuSzYlN2IC0OtZORviTSiEkI1XMyrDm97HQWOCkwa6OizKf/xFdvX5X
12 | xcksALubSX1I+2sUHqP0LbZ3rkxgG6VoaJGF3zZdsjUPfFHBy/IGnbpcMqe/YkZl
13 | AduyI4KhAoGBAP5iLhQr9k/vKUXNgl/9H5wMWBqf3WvOgH4WiApUZ5i5e5JkOgav
14 | 6LSsGdLYhEADYAKYgRUOpwDE6IBcWobTCwe6O0R7Us9r/c1ex3zEPcqiMqULyAxx
15 | LLu34O75t7ctPvhewKfNs16qzl751ZWYInBbQoZf8CkZMDSxsQGCbTIRAoGBAOXO
16 | LOutW0anleTsBbQwbR1k0hIPk6CwQnutq1BcsELYBSNKh6DIA16zBqyE9oFDsS34
17 | VLvXETZZKGEUoPju28DVH+Scic5E15CPNUaJie+Ief97fA/iPLJNJFSpcsJG/+Rd
18 | jB1hurkcvjzp67wNk9z+WJBxcMfAo/KwSxbkNtl7AoGBAKUitycBIvThHLnjny8Q
19 | 8uQqX0dpYCQL+f3gQo/yGw5Z2o494i1VJIuk7V6ij7e+eSU2OxWgXWlyajxpt5qu
20 | hgqOKstaA3gDcs9PJ9Em07YndRkPfN4W2iNCSxLXqRuQk8BIQmiscDSUTUP6i1yB
21 | Vln55EW3IgCMCW8rqux/7sMBAoGAHkrqUvrcIFkxAic2rUUA7TIAGw9gl3sEmIcR
22 | IRvGxFjzfG5zqHcVMqOIyq8QS4Pf1D569PPpue9QylNM0OOzphyyApG7/KvIeq7W
23 | CAFTZHbqFgpyFSnudFaE5oAbt45iZvkJ4kmisooebassPvLPPf9tL0U056/2LKSe
24 | kVrt/AcCgYAWmgeAtQ4H6mX3yPeEa4uDJevjaVKxlKYUPdd8kCD3OTjX9/Pig2GH
25 | XhI5UeVd2k4EBdrY1DRVr+cJ8/fEKzcjOKyrbs0XTld8XCBeVuQKAliYS7PpG70C
26 | 3/jXM8HZyqbPB+apW35Ucqo84ClgPN8LUOi/tE/aP11awxmgTk9F+w==
27 | -----END RSA PRIVATE KEY-----
28 |
--------------------------------------------------------------------------------
/lib/webpay_rails/errors.rb:
--------------------------------------------------------------------------------
1 | module WebpayRails
2 | # Generic WebpayRails exception class.
3 | class WebpayRailsError < StandardError; end
4 |
5 | # Raise when the commerce code has not been defined.
6 | class MissingCommerceCode < WebpayRailsError; end
7 | # Raise when the environment is not valid.
8 | class InvalidEnvironment < WebpayRailsError; end
9 |
10 | # Generic Soap exception class.
11 | class SoapError < WebpayRailsError
12 | def initialize(action, error)
13 | super("Attempted to #{action} but #{error}")
14 | end
15 | end
16 |
17 | # Raise when the SOAP request has failed.
18 | class RequestFailed < SoapError
19 | def initialize(action, error)
20 | super(action, "SOAP responds with a #{error.http.code} " \
21 | "status code: #{error}")
22 | end
23 | end
24 | # Raise when the SOAP response of a request is blank.
25 | class InvalidResponse < SoapError
26 | def initialize(action)
27 | super(action, 'SOAP response is blank')
28 | end
29 | end
30 | # Raise when the SOAP response cannot be verify with the webpay cert.
31 | class InvalidCertificate < SoapError
32 | def initialize(action)
33 | super(action, 'the response was not signed with the correct certificate')
34 | end
35 | end
36 |
37 | # Generic Vault exception class.
38 | class VaultError < WebpayRailsError; end
39 |
40 | # Raise when vault cant load the file.
41 | class FileNotFound < VaultError; end
42 | # Raise when private key has not been defined.
43 | class MissingPrivateKey < VaultError; end
44 | # Raise when public certificate has not been defined.
45 | class MissingPublicCertificate < VaultError; end
46 | # Raise when webpay certificate has not been defined.
47 | class MissingWebpayCertificate < VaultError; end
48 | end
49 |
--------------------------------------------------------------------------------
/lib/webpay_rails/verifier.rb:
--------------------------------------------------------------------------------
1 | module WebpayRails
2 | class Verifier
3 | def self.verify(document, cert)
4 | document = Nokogiri::XML(document.to_s, &:noblanks)
5 | signed_info_node = document.at_xpath('/soap:Envelope/soap:Header/wsse:Security/ds:Signature/ds:SignedInfo', {
6 | ds: 'http://www.w3.org/2000/09/xmldsig#',
7 | wsse: 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd',
8 | soap: 'http://schemas.xmlsoap.org/soap/envelope/'
9 | })
10 |
11 | # check that digest match
12 | check_digest(document, signed_info_node) && check_signature(document, signed_info_node, cert)
13 | end
14 |
15 | def self.check_digest(doc, signed_info_node)
16 | signed_info_node.xpath("//ds:Reference", ds: 'http://www.w3.org/2000/09/xmldsig#').each do |node|
17 | return false if !process_ref_node(doc, node)
18 | end
19 |
20 | true
21 | end
22 |
23 | def self.check_signature(doc, signed_info_node, cert)
24 | signed_info_canon = canonicalize(signed_info_node, ['soap'])
25 | signature = doc.at_xpath('//wsse:Security/ds:Signature/ds:SignatureValue', {
26 | ds: 'http://www.w3.org/2000/09/xmldsig#',
27 | wsse: 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'
28 | }).text
29 |
30 | cert.public_key.verify(OpenSSL::Digest::SHA1.new, Base64.decode64(signature), signed_info_canon)
31 | end
32 |
33 | def self.digest(message)
34 | OpenSSL::Digest::SHA1.new.reset.digest(message)
35 | end
36 |
37 | def self.process_ref_node(doc, node)
38 | uri = node.attr('URI')
39 | element = doc.at_xpath("//*[@wsu:Id='#{uri[1..-1]}']", wsu: 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd')
40 | target = canonicalize(element, nil)
41 | my_digest_value = Base64.encode64(digest(target)).strip
42 | digest_value = node.at_xpath('//ds:DigestValue', ds: 'http://www.w3.org/2000/09/xmldsig#').text
43 |
44 | my_digest_value == digest_value
45 | end
46 |
47 | def self.canonicalize(node = document, inclusive_namespaces=nil)
48 | # The last argument should be exactly +nil+ to remove comments from result
49 | node.canonicalize(Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0, inclusive_namespaces, nil)
50 | end
51 | end
52 | end
53 |
--------------------------------------------------------------------------------
/lib/webpay_rails/soap_oneclick.rb:
--------------------------------------------------------------------------------
1 | module WebpayRails
2 | class SoapOneclick < Soap
3 | def init_inscription(args)
4 | request = client.build_request(:init_inscription,
5 | message: init_inscription_message(args))
6 |
7 | call(request, :init_inscription)
8 | end
9 |
10 | def finish_inscription(args)
11 | request = client.build_request(:finish_inscription,
12 | message: finish_inscription_message(args))
13 |
14 | call(request, :finish_inscription)
15 | end
16 |
17 | def authorize(args)
18 | request = client.build_request(:authorize,
19 | message: authorize_message(args))
20 |
21 | call(request, :authorize)
22 | end
23 |
24 | def reverse(args)
25 | request = client.build_request(:reverse,
26 | message: reverse_message(args))
27 |
28 | call(request, :reverse)
29 | end
30 |
31 | def remove_user(args)
32 | request = client.build_request(:remove_user,
33 | message: remove_user_message(args))
34 |
35 | call(request, :remove_user)
36 | end
37 |
38 | private
39 |
40 | def wsdl_path
41 | case @environment
42 | when :production
43 | 'https://webpay3g.transbank.cl/webpayserver/wswebpay/OneClickPaymentService?wsdl'
44 | when :certification, :integration
45 | 'https://webpay3gint.transbank.cl/webpayserver/wswebpay/OneClickPaymentService?wsdl'
46 | end
47 | end
48 |
49 | def init_inscription_message(args)
50 | {
51 | arg0: {
52 | email: args[:email],
53 | responseURL: args[:return_url],
54 | username: args[:username]
55 | }
56 | }
57 | end
58 |
59 | def finish_inscription_message(args)
60 | {
61 | arg0: {
62 | token: args[:token]
63 | }
64 | }
65 | end
66 |
67 | def authorize_message(args)
68 | {
69 | arg0: {
70 | buyOrder: args[:buy_order],
71 | tbkUser: args[:tbk_user],
72 | username: args[:username],
73 | amount: args[:amount]
74 | }
75 | }
76 | end
77 |
78 | def reverse_message(args)
79 | {
80 | arg0: {
81 | buyorder: args[:buy_order]
82 | }
83 | }
84 | end
85 |
86 | def remove_user_message(args)
87 | {
88 | arg0: {
89 | tbkUser: args[:tbk_user],
90 | username: args[:username]
91 | }
92 | }
93 | end
94 | end
95 | end
96 |
--------------------------------------------------------------------------------
/lib/webpay_rails/soap.rb:
--------------------------------------------------------------------------------
1 | module WebpayRails
2 | class Soap
3 | extend Savon::Model
4 |
5 | def initialize(args)
6 | @vault = args[:vault]
7 | @environment = args[:environment] || :integration
8 | @commerce_code = args[:commerce_code]
9 |
10 | raise WebpayRails::MissingCommerceCode unless @commerce_code
11 |
12 | unless valid_environments.include? @environment
13 | raise WebpayRails::InvalidEnvironment
14 | end
15 |
16 | self.class.client(wsdl: wsdl_path, log: args[:log] || true,
17 | logger: file_logger.extend(rails_logger),
18 | open_timeout: 15, read_timeout: 15)
19 | end
20 |
21 | private
22 |
23 | def call(request, operation)
24 | signed_document = sign_xml(request)
25 |
26 | response = client.call(operation) do
27 | xml signed_document.to_xml(save_with: 0)
28 | end
29 |
30 | verify_response(response, operation)
31 | rescue Savon::SOAPFault => error
32 | raise WebpayRails::RequestFailed.new(operation, error)
33 | end
34 |
35 | def sign_xml(input_xml)
36 | document = Nokogiri::XML(input_xml.body)
37 | envelope = document.at_xpath('//env:Envelope')
38 | envelope.prepend_child('')
39 | xml = document.to_s
40 |
41 | signer = Signer.new(xml)
42 |
43 | signer.cert = @vault.public_cert
44 | signer.private_key = @vault.private_key
45 |
46 | signer.document.xpath('//soapenv:Body', { soapenv: 'http://schemas.xmlsoap.org/soap/envelope/' }).each do |node|
47 | signer.digest!(node)
48 | end
49 |
50 | signer.sign!(issuer_serial: true)
51 | signed_xml = signer.to_xml
52 |
53 | document = Nokogiri::XML(signed_xml)
54 | x509data = document.at_xpath('//*[local-name()=\'X509Data\']')
55 | new_data = x509data.clone
56 | new_data.set_attribute('xmlns:ds', 'http://www.w3.org/2000/09/xmldsig#')
57 |
58 | n = Nokogiri::XML::Node.new('wsse:SecurityTokenReference', document)
59 | n.add_child(new_data)
60 | x509data.add_next_sibling(n)
61 |
62 | document
63 | end
64 |
65 | def verify_response(response, operation)
66 | raise(WebpayRails::InvalidResponse, operation) if response.blank?
67 |
68 | if WebpayRails::Verifier.verify(response, @vault.webpay_cert)
69 | response
70 | else
71 | raise WebpayRails::InvalidCertificate, operation
72 | end
73 | end
74 |
75 | def valid_environments
76 | [:production, :certification, :integration]
77 | end
78 |
79 | def rails_logger
80 | ActiveSupport::Logger.broadcast(WebpayRails.rails_logger)
81 | end
82 |
83 | def file_logger
84 | Logger.new(Rails.root.join("log/webpay.log"))
85 | end
86 | end
87 | end
88 |
--------------------------------------------------------------------------------
/spec/internal/app/controllers/normal_orders_controller.rb:
--------------------------------------------------------------------------------
1 | class NormalOrdersController < ActionController::Base
2 | before_action :find_order, only: [:return, :final]
3 | before_action :verify_order, only: :return
4 |
5 | def new
6 | @order = Order::Normal.new
7 | end
8 |
9 | def create
10 | @order = Order::Normal.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::Normal.find(params[:id])
49 | end
50 |
51 | def create_params
52 | params.require(:order_normal).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::Normal.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::Normal.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_normal,
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
108 |
--------------------------------------------------------------------------------
/spec/oneclick_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 | require 'vault_helper'
3 |
4 | describe 'Inscription flow' do
5 | let(:email) { 'john.doe@mail.com' }
6 | let(:username) { 'john' }
7 |
8 | before(:each) { visit new_oneclick_inscription_path }
9 |
10 | context 'when it accepted' do
11 | it 'it is sent to the success page' do
12 | # Rails app
13 | fill_in(id: 'user_email', with: email)
14 | fill_in(id: 'user_username', with: username)
15 | find('input[type=submit]').click
16 |
17 | # Webpay
18 | fill_in('TBK_NUMERO_TARJETA', with: '4051885600446623')
19 | fill_in('TBK_CVV', with: '123')
20 | click_button('button')
21 |
22 | # Demo Bank
23 | within_frame('transicion') do
24 | fill_in('rutClient', with: '111111111')
25 | fill_in('passwordClient', with: '123')
26 | find('input[type=submit]').click
27 | # It is not necessary because it is already selected by default
28 | # select('Aceptar', from: 'vci')
29 | find('input[type=submit]').click
30 | end
31 |
32 | # Webpay
33 | accept_alert if page.driver.options[:browser] == :firefox
34 |
35 | # Rails app
36 | expect(page).to have_content('Success inscription')
37 | end
38 | end
39 |
40 | context 'when it rejected' do
41 | it 'it is sent to the failure page' do
42 | # Rails app
43 | fill_in(id: 'user_email', with: email)
44 | fill_in(id: 'user_username', with: username)
45 | find('input[type=submit]').click
46 |
47 | # Webpay
48 | fill_in('TBK_NUMERO_TARJETA', with: '4051885600446623')
49 | fill_in('TBK_CVV', with: '123')
50 | click_button('button')
51 |
52 | # Demo Bank
53 | within_frame('transicion') do
54 | fill_in('rutClient', with: '111111111')
55 | fill_in('passwordClient', with: '123')
56 | find('input[type=submit]').click
57 |
58 | select('Rechazar', from: 'vci')
59 | find('input[type=submit]').click
60 | end
61 |
62 | # Webpay
63 | accept_alert if page.driver.options[:browser] == :firefox
64 |
65 | # Rails app
66 | expect(page).to have_content('Failed inscription')
67 | end
68 | end
69 | end
70 |
71 | describe 'Authorization flow' do
72 | before(:each) { visit new_oneclick_order_path }
73 |
74 | context 'when it accepted' do
75 | it 'it is sent to the success page' do
76 | # Rails app
77 | fill_in(id: 'order_oneclick_amount', with: '1000')
78 | find('input[type=submit]').click
79 |
80 | # Webpay
81 | accept_alert if page.driver.options[:browser] == :firefox
82 |
83 | # Rails app
84 | expect(page).to have_content('Success transaction')
85 | end
86 | end
87 | end
88 |
89 | describe 'Reverse order' do
90 | before(:all) { @buy_order = Order::Oneclick.approved.last!.buy_order_for_transbank_oneclick }
91 |
92 | context 'when all is ok' do
93 | before(:all) { @result = Order::Oneclick.reverse(buy_order: @buy_order) }
94 |
95 | it { expect(@result).to be_kind_of(WebpayRails::Responses::Reverse) }
96 | it { expect(@result.success?).to be_truthy }
97 |
98 | describe '.return' do
99 | it { expect(@result.return).not_to be_blank }
100 | end
101 | end
102 |
103 | context 'when not' do
104 | it { expect { Order::Oneclick.reverse(buy_order: '') }.to raise_error(WebpayRails::RequestFailed) }
105 | pending 'should raise WebpayRails::InvalidCertificate'
106 | end
107 | end
108 |
109 | describe 'Unsubscribe' do
110 | before(:all) { @tbk_user = User.first!.tbk_user }
111 | before(:all) { @username = 'john' }
112 |
113 | context 'when all is ok' do
114 | before(:all) { @result = Order::Oneclick.remove_user(tbk_user: @tbk_user, username: @username) }
115 |
116 | it { expect(@result).to be_kind_of(WebpayRails::Responses::RemoveUser) }
117 | it { expect(@result.success?).to be_truthy }
118 |
119 | describe '.return' do
120 | it { expect(@result.return).not_to be_blank }
121 | end
122 | end
123 |
124 | context 'when not' do
125 | it { expect { Order::Oneclick.remove_user(tbk_user: '', username: @username) }.to raise_error(WebpayRails::RequestFailed) }
126 | pending 'should raise WebpayRails::InvalidCertificate'
127 | end
128 | end
129 |
--------------------------------------------------------------------------------
/spec/vault_helper.rb:
--------------------------------------------------------------------------------
1 | COMMERCE_CODE = 597020000541
2 | PRIVATE_KEY = '-----BEGIN RSA PRIVATE KEY-----
3 | MIIEpQIBAAKCAQEA0ClVcH8RC1u+KpCPUnzYSIcmyXI87REsBkQzaA1QJe4w/B7g
4 | 6KvKV9DaqfnNhMvd9/ypmGf0RDQPhlBbGlzymKz1xh0lQBD+9MZrg8Ju8/d1k0pI
5 | b1QLQDnhRgR2T14ngXpP4PIQKtq7DsdHBybFU5vvAKVqdHvImZFzqexbZjXWxxhT
6 | +/sGcD4Vs673fc6B+Xj2UrKF7QyV5pMDq0HCCLTMmafWAmNrHyl6imQM+bqC12gn
7 | EEAEkrJiSO6P/21m9iDJs5KQanpJby0aGW8mocYRHDMHZjtTiIP0+JAJgL9KsH+r
8 | Xdk2bT7aere7TzOK/bEwhkYEXnMMt/65vV6AfwIDAQABAoIBAHnIlOn6DTi99eXl
9 | KVSzIb5dA747jZWMxFruL70ifM+UKSh30FGPoBP8ZtGnCiw1ManSMk6uEuSMKMEF
10 | 5iboVi4okqnTh2WSC/ec1m4BpPQqxKjlfrdTTjnHIxrZpXYNucMwkeci93569ZFR
11 | 2SY/8pZV1mBkZoG7ocLmq+qwE1EaBEL/sXMvuF/h08nJ71I4zcclpB8kN0yFrBCW
12 | 7scqOwTLiob2mmU2bFHOyyjTkGOlEsBQxhtVwVEt/0AFH/ucmMTP0vrKOA0HkhxM
13 | oeR4k2z0qwTzZKXuEZtsau8a/9B3S3YcgoSOhRP/VdY1WL5hWDHeK8q1Nfq2eETX
14 | jnQ4zjECgYEA7z2/biWe9nDyYDZM7SfHy1xF5Q3ocmv14NhTbt8iDlz2LsZ2JcPn
15 | EMV++m88F3PYdFUOp4Zuw+eLJSrBqfuPYrTVNH0v/HdTqTS70R2YZCFb9g0ryaHV
16 | TRwYovu/oQMV4LBSzrwdtCrcfUZDtqMYmmZfEkdjCWCEpEi36nlG0JMCgYEA3r49
17 | o+soFIpDqLMei1tF+Ah/rm8oY5f4Wc82kmSgoPFCWnQEIW36i/GRaoQYsBp4loue
18 | vyPuW+BzoZpVcJDuBmHY3UOLKr4ZldOn2KIj6sCQZ1mNKo5WuZ4YFeL5uyp9Hvio
19 | TCPGeXghG0uIk4emSwolJVSbKSRi6SPsiANff+UCgYEAvNMRmlAbLQtsYb+565xw
20 | NvO3PthBVL4dLL/Q6js21/tLWxPNAHWklDosxGCzHxeSCg9wJ40VM4425rjebdld
21 | DF0Jwgnkq/FKmMxESQKA2tbxjDxNCTGv9tJsJ4dnch/LTrIcSYt0LlV9/WpN24LS
22 | 0lpmQzkQ07/YMQosDuZ1m/0CgYEAu9oHlEHTmJcO/qypmu/ML6XDQPKARpY5Hkzy
23 | gj4ZdgJianSjsynUfsepUwK663I3twdjR2JfON8vxd+qJPgltf45bknziYWvgDtz
24 | t/Duh6IFZxQQSQ6oN30MZRD6eo4X3dHp5eTaE0Fr8mAefAWQCoMw1q3m+ai1PlhM
25 | uFzX4r0CgYEArx4TAq+Z4crVCdABBzAZ7GvvAXdxvBo0AhD9IddSWVTCza972wta
26 | 5J2rrS/ye9Tfu5j2IbTHaLDz14mwMXr1S4L39UX/NifLc93KHie/yjycCuu4uqNo
27 | MtdweTnQt73lN2cnYedRUhw9UTfPzYu7jdXCUAyAD4IEjFQrswk2x04=
28 | -----END RSA PRIVATE KEY-----'.freeze
29 | PUBLIC_CERT = '-----BEGIN CERTIFICATE-----
30 | MIIDujCCAqICCQCZ42cY33KRTzANBgkqhkiG9w0BAQsFADCBnjELMAkGA1UEBhMC
31 | Q0wxETAPBgNVBAgMCFNhbnRpYWdvMRIwEAYDVQQKDAlUcmFuc2JhbmsxETAPBgNV
32 | BAcMCFNhbnRpYWdvMRUwEwYDVQQDDAw1OTcwMjAwMDA1NDExFzAVBgNVBAsMDkNh
33 | bmFsZXNSZW1vdG9zMSUwIwYJKoZIhvcNAQkBFhZpbnRlZ3JhZG9yZXNAdmFyaW9z
34 | LmNsMB4XDTE2MDYyMjIxMDkyN1oXDTI0MDYyMDIxMDkyN1owgZ4xCzAJBgNVBAYT
35 | AkNMMREwDwYDVQQIDAhTYW50aWFnbzESMBAGA1UECgwJVHJhbnNiYW5rMREwDwYD
36 | VQQHDAhTYW50aWFnbzEVMBMGA1UEAwwMNTk3MDIwMDAwNTQxMRcwFQYDVQQLDA5D
37 | YW5hbGVzUmVtb3RvczElMCMGCSqGSIb3DQEJARYWaW50ZWdyYWRvcmVzQHZhcmlv
38 | cy5jbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANApVXB/EQtbviqQ
39 | j1J82EiHJslyPO0RLAZEM2gNUCXuMPwe4OirylfQ2qn5zYTL3ff8qZhn9EQ0D4ZQ
40 | Wxpc8pis9cYdJUAQ/vTGa4PCbvP3dZNKSG9UC0A54UYEdk9eJ4F6T+DyECrauw7H
41 | RwcmxVOb7wClanR7yJmRc6nsW2Y11scYU/v7BnA+FbOu933Ogfl49lKyhe0MleaT
42 | A6tBwgi0zJmn1gJjax8peopkDPm6gtdoJxBABJKyYkjuj/9tZvYgybOSkGp6SW8t
43 | GhlvJqHGERwzB2Y7U4iD9PiQCYC/SrB/q13ZNm0+2nq3u08ziv2xMIZGBF5zDLf+
44 | ub1egH8CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAdgNpIS2NZFx5PoYwJZf8faze
45 | NmKQg73seDGuP8d8w/CZf1Py/gsJFNbh4CEySWZRCzlOKxzmtPTmyPdyhObjMA8E
46 | Adps9DtgiN2ITSF1HUFmhMjI5V7U2L9LyEdpUaieYyPBfxiicdWz2YULVuOYDJHR
47 | n05jlj/EjYa5bLKs/yggYiqMkZdIX8NiLL6ZTERIvBa6azDKs6yDsCsnE1M5tzQI
48 | VVEkZtEfil6E1tz8v3yLZapLt+8jmPq1RCSx3Zh4fUkxBTpUW/9SWUNEXbKK7bB3
49 | zfB3kGE55K5nxHKfQlrqdHLcIo+vdShATwYnmhUkGxUnM9qoCDlB8lYu3rFi9w==
50 | -----END CERTIFICATE-----'.freeze
51 | WEBPAY_CERT = '-----BEGIN CERTIFICATE-----
52 | MIIDKTCCAhECBFZl7uIwDQYJKoZIhvcNAQEFBQAwWTELMAkGA1UEBhMCQ0wxDjAMBgNVBAgMBUNo
53 | aWxlMREwDwYDVQQHDAhTYW50aWFnbzEMMAoGA1UECgwDa2R1MQwwCgYDVQQLDANrZHUxCzAJBgNV
54 | BAMMAjEwMB4XDTE1MTIwNzIwNDEwNloXDTE4MDkwMjIwNDEwNlowWTELMAkGA1UEBhMCQ0wxDjAM
55 | BgNVBAgMBUNoaWxlMREwDwYDVQQHDAhTYW50aWFnbzEMMAoGA1UECgwDa2R1MQwwCgYDVQQLDANr
56 | ZHUxCzAJBgNVBAMMAjEwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAizJUWTDC7nfP
57 | 3jmZpWXFdG9oKyBrU0Bdl6fKif9a1GrwevThsU5Dq3wiRfYvomStNjFDYFXOs9pRIxqX2AWDybjA
58 | X/+bdDTVbM+xXllA9stJY8s7hxAvwwO7IEuOmYDpmLKP7J+4KkNH7yxsKZyLL9trG3iSjV6Y6SO5
59 | EEhUsdxoJFAow/h7qizJW0kOaWRcljf7kpqJAL3AadIuqV+hlf+Ts/64aMsfSJJA6xdbdp9ddgVF
60 | oqUl1M8vpmd4glxlSrYmEkbYwdI9uF2d6bAeaneBPJFZr6KQqlbbrVyeJZqmMlEPy0qPco1TIxrd
61 | EHlXgIFJLyyMRAyjX9i4l70xjwIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQBn3tUPS6e2USgMrPKp
62 | sxU4OTfW64+mfD6QrVeBOh81f6aGHa67sMJn8FE/cG6jrUmX/FP1/Cpbpvkm5UUlFKpgaFfHv+Kg
63 | CpEvgcRIv/OeIi6Jbuu3NrPdGPwzYkzlOQnmgio5RGb6GSs+OQ0mUWZ9J1+YtdZc+xTga0x7nsCT
64 | 5xNcUXsZKhyjoKhXtxJm3eyB3ysLNyuL/RHy/EyNEWiUhvt1SIePnW+Y4/cjQWYwNqSqMzTSW9TP
65 | 2QR2bX/W2H6ktRcLsgBK9mq7lE36p3q6c9DtZJE+xfA4NGCYWM9hd8pbusnoNO7AFxJZOuuvLZI7
66 | JvD7YLhPvCYKry7N6x3l
67 | -----END CERTIFICATE-----'.freeze
68 |
--------------------------------------------------------------------------------
/lib/webpay_rails/base.rb:
--------------------------------------------------------------------------------
1 | module WebpayRails
2 | module Base
3 | extend ActiveSupport::Concern
4 | module ClassMethods
5 | # Setup a model for use Webpay Rails.
6 | #
7 | # ==== Variations of #webpay_rails
8 | #
9 | # # setup with certificates and private_key content
10 | # webpay_rails(
11 | # commerce_code: 123456789,
12 | # private_key: '-----BEGIN RSA PRIVATE KEY-----
13 | # ...
14 | # -----END RSA PRIVATE KEY-----',
15 | # public_cert: '-----BEGIN CERTIFICATE-----
16 | # ...
17 | # -----END CERTIFICATE-----',
18 | # webpay_cert: '-----BEGIN CERTIFICATE-----
19 | # ...
20 | # -----END CERTIFICATE-----',
21 | # environment: :integration,
22 | # log: true
23 | # )
24 | #
25 | # # setup with certificates and private_key files
26 | # webpay_rails(
27 | # commerce_code: 123456789,
28 | # private_key: 'absolute/path/to/private_key.key',
29 | # public_cert: 'absolute/path/to/public_cert.crt',
30 | # webpay_cert: 'absolute/path/to/webpay_cert.crt',
31 | # environment: :integration,
32 | # log: true
33 | # )
34 | def webpay_rails(args)
35 | class_attribute :vault, :soap_normal, :soap_nullify, :soap_oneclick,
36 | instance_accessor: false
37 |
38 | self.vault = args[:vault] = WebpayRails::Vault.new(args)
39 | self.soap_normal = WebpayRails::SoapNormal.new(args)
40 | self.soap_nullify = WebpayRails::SoapNullify.new(args)
41 | self.soap_oneclick = WebpayRails::SoapOneclick.new(args)
42 | end
43 |
44 | # Initializes a transaction
45 | # Returns a WebpayRails::Response::InitTransaction if successfully initialised.
46 | # If fault a WebpayRails::RequestFailed exception is raised.
47 | # If the SOAP response cant be verified a WebpayRails::InvalidCertificate
48 | # exception is raised.
49 | #
50 | # === Arguments
51 | # [:amount]
52 | # An integer that define the amount of the transaction.
53 | # [:buy_order]
54 | # An string that define the order number of the buy.
55 | # [:session_id]
56 | # An string that define a local variable that will be returned as
57 | # part of the result of the transaction.
58 | # [:return_url]
59 | # An string that define the url that Webpay redirect after client is
60 | # authorized (or not) by the bank for get the result of the transaction.
61 | # [:final_url]
62 | # An string that define the url that Webpay redirect after they show
63 | # the webpay invoice, or cancel the transaction from Webpay.
64 | def init_transaction(args)
65 | response = soap_normal.init_transaction(args)
66 |
67 | WebpayRails::Responses::InitTransaction.new(response)
68 | end
69 |
70 | # Retrieves the result of a transaction
71 | # Returns a WebpayRails::Response::TransactionResult if successfully get a response.
72 | # If fault a WebpayRails::RequestFailed exception is raised.
73 | # If the SOAP response cant be verified a WebpayRails::InvalidCertificate
74 | # exception is raised.
75 | #
76 | # === Arguments
77 | # [:token]
78 | # An string that responds Webpay when redirect to +return_url+.
79 | # [:ack]
80 | # An optional boolean with which you can disable the auto
81 | # acknowledgement (I guess if you do this, you will know what you do).
82 | def transaction_result(args)
83 | response = soap_normal.get_transaction_result(args)
84 |
85 | acknowledge_transaction(args) if args[:ack] != false
86 |
87 | WebpayRails::Responses::TransactionResult.new(response)
88 | end
89 |
90 | # Reports the correct reception of the result of the transaction
91 | # If fault a WebpayRails::RequestFailed exception is raised.
92 | # If the SOAP response cant be verified a WebpayRails::InvalidCertificate
93 | # exception is raised.
94 | #
95 | # === Arguments
96 | # [:token]
97 | # An string that responds Webpay when redirect to +return_url+.
98 | #
99 | # NOTE: It is not necessary to use this method because it is consumed by
100 | # +transaction_result+.
101 | def acknowledge_transaction(args)
102 | soap_normal.acknowledge_transaction(args)
103 | end
104 |
105 | # Nullify a transaction
106 | # Returns a WebpayRails::Response::TransactionNullify if successfully initialised.
107 | # If fault a WebpayRails::RequestFailed exception is raised.
108 | # If the SOAP response cant be verified a WebpayRails::InvalidCertificate
109 | # exception is raised.
110 | #
111 | # === Arguments
112 | # [:authorization_code]
113 | # An string that original belongs to the transaction.
114 | # [:authorize_amount]
115 | # An integer that define the original amount of the transaction.
116 | # [:buy_order]
117 | # An string that define the order number of the transaction to be
118 | # nullified.
119 | # [:nullify_amount]
120 | # An intenger that define the amount to be nullified on the transaction.
121 | def nullify(args)
122 | response = soap_nullify.nullify(args)
123 |
124 | WebpayRails::Responses::TransactionNullify.new(response)
125 | end
126 |
127 | def init_inscription(args)
128 | response = soap_oneclick.init_inscription(args)
129 |
130 | WebpayRails::Responses::InitInscription.new(response)
131 | end
132 |
133 | def finish_inscription(args)
134 | response = soap_oneclick.finish_inscription(args)
135 |
136 | WebpayRails::Responses::FinishInscription.new(response)
137 | end
138 |
139 | def authorize(args)
140 | response = soap_oneclick.authorize(args)
141 |
142 | WebpayRails::Responses::Authorization.new(response)
143 | end
144 |
145 | def reverse(args)
146 | response = soap_oneclick.reverse(args)
147 |
148 | WebpayRails::Responses::Reverse.new(response)
149 | end
150 |
151 | def remove_user(args)
152 | response = soap_oneclick.remove_user(args)
153 |
154 | WebpayRails::Responses::RemoveUser.new(response)
155 | end
156 | end
157 | end
158 | end
159 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # WebpayRails
2 |
3 | [](https://travis-ci.org/limcross/webpay_rails)
4 | [](https://codeclimate.com/github/limcross/webpay_rails)
5 | [](https://coveralls.io/github/limcross/webpay_rails?branch=master)
6 | [](https://gemnasium.com/github.com/limcross/webpay_rails)
7 | [](https://badge.fury.io/rb/webpay_rails)
8 |
9 | WebpayRails is an easy solution for integrate Transbank Webpay in Rails applications.
10 |
11 | _This gem (including certificates used in tests) was originally based on the SDK for Ruby (distributed under the **open source license**) available in www.transbankdevelopers.cl_
12 |
13 | ### WebpayRails has been Deprecated
14 |
15 | __Transbank no longer supports SOAP integration. This repository has been deprecated and will no longer be maintained.__
16 |
17 | You should consider using the official gem [transbank-sdk-ruby](https://github.com/TransbankDevelopers/transbank-sdk-ruby).
18 |
19 | ## Getting started
20 |
21 | __This README is only valid for the *master* branch, click [here](https://github.com/limcross/webpay_rails/blob/v1.1.1/README.md) for see the latest released version.__
22 |
23 | You can add it to your `Gemfile`:
24 |
25 | ```ruby
26 | gem 'webpay_rails'
27 | ```
28 |
29 | Run the bundle command to install it.
30 |
31 | ### Configuring models
32 | After that, extend the model to `WebpayRails` and add `webpay_rails` to this, like below.
33 |
34 | ```ruby
35 | class Order < ActiveRecord::Base
36 | extend WebpayRails
37 |
38 | webpay_rails(
39 | commerce_code: 123456789,
40 | private_key: '-----BEGIN RSA PRIVATE KEY-----
41 | ...
42 | -----END RSA PRIVATE KEY-----',
43 | public_cert: '-----BEGIN CERTIFICATE-----
44 | ...
45 | -----END CERTIFICATE-----',
46 | webpay_cert: '-----BEGIN CERTIFICATE-----
47 | ...
48 | -----END CERTIFICATE-----',
49 | environment: :integration,
50 | log: true
51 | )
52 | end
53 | ```
54 |
55 | As you can see for `private_key`, `public_cert`, and `webpay_cert`, the content of the files is entered, without prejudice to the above you can also indicate the absolute path to these files.
56 |
57 | The default `environment` is `:integration`, and the valid environments are `:integration`, `:certification` and `:production`. Depending on the environment is assigned the wsdl path.
58 |
59 | The `log` is very useful when generating the evidence of integration, and is enabled by default. The log can be found both in the rails log and in a separate file (`log\webpay.log`).
60 |
61 | Obviously all these values should not be defined directly in the model. It is strongly recommended to use environment variables for this ([dotenv](https://github.com/bkeepers/dotenv)).
62 |
63 | ### Using WebpayRails
64 |
65 | #### Initializing a transaction
66 |
67 | First we need to initialize an transaction, like below:
68 |
69 | ```ruby
70 | @transaction = Order.init_transaction(amount: amount, buy_order: buy_order, session_id: session_id, return_url: return_url, final_url: final_url)
71 | ```
72 |
73 | Where `amount` is an __integer__ that define the amount of the transaction (_obviously_), `buy_order` is an __string__ that define the order number of the buy, `session_id` is an __string__ that define a local variable that will be returned as part of the result of the transaction, `return_url` and `final_url` are a __string__ for the redirections.
74 |
75 | This method return a `Transaction` object, that contain a redirection `url` and `token` for redirect the customer through POST method, like below.
76 |
77 | ```erb
78 | <% if @transaction.success? %>
79 | <%= form_tag(@transaction.url, method: :post, enforce_utf8: false, authenticity_token: false) do %>
80 | <%= hidden_field_tag(:token_ws, @transaction.token) %>
81 | <%= submit_tag("Pagar con Webpay") %>
82 | <% end %>
83 | <% end %>
84 | ```
85 |
86 | Once Webpay displays the form of payment and authorization of the bank, the customer will send back through __POST__ method to the `return_url` with a `token_ws`. (If the customer cancels the transaction is directly returned to the `final_url` in the same way).
87 |
88 | #### Getting the result of a transaction
89 |
90 | When Webpay send a __POST__ to `return_url` with `token_ws`, we need to ask for the transaction result, like below.
91 |
92 | ```ruby
93 | @result = Order.transaction_result(token: params[:token_ws])
94 | ```
95 |
96 | This method return a `TransactionResult` object, that contain an `buy_order`, `session_id`, `accounting_date`, `transaction_date`, `vci`, `url_redirection`, `card_number`, `card_expiration_date`, `authorization_code`, `payment_type_code`, `response_code`, `amount`, `shares_number` and `commerce_code`.
97 |
98 | At this point we have confirmed the transaction with Transbank, performing the operation `acknowledge_transaction` by means of `transaction_result`.
99 |
100 | Now we need to send back the customer to `url_redirection` with `token_ws` through __GET__ method.
101 |
102 | #### Ending a transaction
103 |
104 | When Webpay send customer to `final_url`, we are done. Finally the transaction has ended. :clap:
105 |
106 | #### Nullify a transaction
107 |
108 | To cancel a transaction we must use the method described below.
109 |
110 | ```ruby
111 | @transaction = Order.nullify(authorization_code: authorization_code, authorized_amount: authorized_amount, buy_order: buy_order, nullify_amount: nullify_amount)
112 | ```
113 |
114 | Where `authorization_code`, `authorized_amount`, `buy_order`, are known and corresponds to the transaction to be canceled, and `nullify_amount` it corresponds to the amount to be canceled.
115 |
116 | This method return a `TransactionNullified` object, that contain an `token`, `authorization_code`, `authorization_date`, `balance` and
117 | `nullified_amount`.
118 |
119 | Note that you can only make a single cancellation, whether total or partial.
120 |
121 | ## Contributing
122 | Any contribution is welcome. Personally I prefer to use English to do documentation and describe commits, however there is no problem if you make your comments and issues in Spanish.
123 |
124 | ### Reporting issues
125 |
126 | Please try to answer the following questions in your bug report:
127 |
128 | - What did you do?
129 | - What did you expect to happen?
130 | - What happened instead?
131 |
132 | Make sure to include as much relevant information as possible. Ruby version,
133 | WebpayRails version, OS version and any stack traces you have are very valuable.
134 |
135 | ### Pull Requests
136 |
137 | - __Add tests!__ Your patch won't be accepted if it doesn't have tests.
138 |
139 | - __Document any change in behaviour__. Make sure the README and any relevant documentation are kept up-to-date.
140 |
141 | - __Create topic branches__. Please don't ask us to pull from your master branch.
142 |
143 | - __One pull request per feature__. If you want to do more than one thing, send multiple pull requests.
144 |
145 | - __Send coherent history__. Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please squash them before sending them to us.
146 |
--------------------------------------------------------------------------------
/spec/normal_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 | require 'vault_helper'
3 |
4 | describe WebpayRails::Responses::InitTransaction do
5 | let(:amount) { 1000 }
6 | let(:buy_order) { SecureRandom.uuid.first(30).delete!('-') }
7 | let(:session_id) { 'aj2h4kj2' }
8 | let(:return_url) { 'http://localhost:3000/tbknormal?option=return' }
9 | let(:final_url) { 'http://localhost:3000/tbknormal?option=final' }
10 | let(:init_transaction_params) do
11 | { amount: amount,
12 | buy_order: buy_order,
13 | session_id: session_id,
14 | return_url: return_url,
15 | final_url: final_url }
16 | end
17 | context 'when all is ok' do
18 | let!(:transaction) { Order::Normal.init_transaction(init_transaction_params) }
19 |
20 | it { expect(transaction).to be_kind_of(WebpayRails::Responses::InitTransaction) }
21 |
22 | describe '.token' do
23 | it { expect(transaction.token).not_to be_blank }
24 | end
25 |
26 | describe '.url' do
27 | it { expect(transaction.url).not_to be_blank }
28 | end
29 |
30 | describe '.success?' do
31 | it { expect(transaction.success?).to be_truthy }
32 | end
33 | end
34 |
35 | context 'when not' do
36 | it { expect { Order::Normal.init_transaction(init_transaction_params.merge(return_url: '', final_url: '')) }.to raise_error(WebpayRails::RequestFailed) }
37 | it { expect { Order::Normal.init_transaction(init_transaction_params.merge(amount: 0)) }.to raise_error(WebpayRails::RequestFailed) }
38 | it { expect { Order::NormalInvalid.init_transaction(init_transaction_params) }.to raise_error(WebpayRails::InvalidCertificate) }
39 | end
40 | end
41 |
42 | describe WebpayRails::Responses::TransactionResult do
43 | context 'when all is ok' do
44 | describe '.buy_order' do
45 | pending 'should not be blank'
46 | end
47 |
48 | describe '.session_id' do
49 | # pending 'should not be blank' NOTE: In fact it can
50 | end
51 |
52 | describe '.accounting_date' do
53 | pending 'should not be blank'
54 | end
55 |
56 | describe '.transaction_date' do
57 | pending 'should not be blank'
58 | end
59 |
60 | describe '.vci' do
61 | pending 'should not be blank'
62 | end
63 |
64 | describe '.url_redirection' do
65 | pending 'should not be blank'
66 | end
67 |
68 | describe '.card_number' do
69 | pending 'should not be blank'
70 | end
71 |
72 | describe '.card_expiration_date' do
73 | # pending 'should not be blank' NOTE: In fact Webpay returns blank
74 | end
75 |
76 | describe '.authorization_code' do
77 | pending 'should not be blank'
78 | end
79 |
80 | describe '.payment_type_code' do
81 | pending 'should not be blank'
82 | end
83 |
84 | describe '.response_code' do
85 | pending 'should not be blank'
86 | end
87 |
88 | describe '.amount' do
89 | pending 'should not be blank'
90 | end
91 |
92 | describe '.shares_number' do
93 | pending 'should not be blank'
94 | end
95 |
96 | describe '.commerce_code' do
97 | pending 'should not be blank'
98 | end
99 |
100 | describe '.approved?' do
101 | pending 'should be truthy'
102 | end
103 | end
104 |
105 | context 'when not' do
106 | it { expect { Order::Normal.init_transaction(token: 'asd') }.to raise_error(WebpayRails::RequestFailed) }
107 | pending 'should raise WebpayRails::InvalidCertificate'
108 | end
109 | end
110 |
111 | describe 'Normal debit payment flow' do
112 | before(:each) { visit new_normal_order_path }
113 |
114 | context 'when it accepted' do
115 | it 'it is sent to the success page' do
116 | # Rails app
117 | fill_in(id: 'order_normal_amount', with: '1000')
118 | find('input[type=submit]').click
119 |
120 | # Webpay
121 | find('input#TBK_TIPO_TARJETA[value=DEBIT_CARD]').set(true)
122 | select('TEST COMMERCE BANK', from: 'TBK_BANCO')
123 | fill_in('TBK_NUMERO_TARJETA', with: '12345678')
124 | click_button('button')
125 |
126 | # Demo Bank
127 | within_frame('transicion') do
128 | fill_in('rutClient', with: '111111111')
129 | fill_in('passwordClient', with: '123')
130 | find('input[type=submit]').click
131 | # It is not necessary because it is already selected by default
132 | # select('Aceptar', from: 'vci')
133 | find('input[type=submit]').click
134 | end
135 |
136 | # Webpay
137 | accept_alert if page.driver.options[:browser] == :firefox
138 | click_button('button4')
139 | accept_alert if page.driver.options[:browser] == :firefox
140 |
141 | # Rails app
142 | expect(page).to have_content('Success transaction')
143 | end
144 | end
145 |
146 | context 'when it rejected' do
147 | it 'it is sent to the failure page' do
148 | # Rails app
149 | fill_in(id: 'order_normal_amount', with: '1000')
150 | find('input[type=submit]').click
151 |
152 | # Webpay
153 | find('input#TBK_TIPO_TARJETA[value=DEBIT_CARD]').set(true)
154 | select('TEST COMMERCE BANK', from: 'TBK_BANCO')
155 | fill_in('TBK_NUMERO_TARJETA', with: '12345678')
156 | click_button('button')
157 |
158 | # Demo Bank
159 | within_frame('transicion') do
160 | fill_in('rutClient', with: '111111111')
161 | fill_in('passwordClient', with: '123')
162 | find('input[type=submit]').click
163 |
164 | select('Rechazar', from: 'vci')
165 | find('input[type=submit]').click
166 | end
167 |
168 | # Webpay
169 | accept_alert if page.driver.options[:browser] == :firefox
170 |
171 | # Rails app
172 | expect(page).to have_content('Failed transaction')
173 | end
174 | end
175 |
176 | context 'when click on the "Anular" button' do
177 | it 'it is sent to the failure page' do
178 | # Rails app
179 | fill_in(id: 'order_normal_amount', with: '1000')
180 | find('input[type=submit]').click
181 |
182 | # Webpay
183 | click_button('button3')
184 | accept_alert if page.driver.options[:browser] == :firefox
185 |
186 | # Rails app
187 | expect(page).to have_content('Failed transaction')
188 | end
189 | end
190 | end
191 |
192 | describe 'Normal credit (without shares) payment flow' do
193 | before(:each) { visit '/' }
194 |
195 | context 'when it accepted' do
196 | it 'it is sent to the success page' do
197 | # Rails app
198 | fill_in(id: 'order_normal_amount', with: '1000')
199 | find('input[type=submit]').click
200 |
201 | # Webpay
202 | find('input#TBK_TIPO_TARJETA[value=CREDIT_CARD]').set(true)
203 | fill_in('TBK_NUMERO_TARJETA', with: '4051885600446623')
204 | fill_in('TBK_CVV', with: '123')
205 | shares_radio = find('input#TBK_TIPO_PAGO597020000541_noshares')
206 | expect(shares_radio).to be_checked
207 | click_button('button')
208 |
209 | # Demo Bank
210 | within_frame('transicion') do
211 | fill_in('rutClient', with: '111111111')
212 | fill_in('passwordClient', with: '123')
213 | find('input[type=submit]').click
214 | # It is not necessary because it is already selected by default
215 | # select('Aceptar', from: 'vci')
216 | find('input[type=submit]').click
217 | end
218 |
219 | # Webpay
220 | accept_alert if page.driver.options[:browser] == :firefox
221 | click_button('button4')
222 | accept_alert if page.driver.options[:browser] == :firefox
223 |
224 | # Rails app
225 | expect(page).to have_content('Success transaction')
226 | end
227 | end
228 |
229 | context 'when it rejected' do
230 | it 'it is sent to the failure page' do
231 | # Rails app
232 | fill_in(id: 'order_normal_amount', with: '1000')
233 | find('input[type=submit]').click
234 |
235 | # Webpay
236 | find('input#TBK_TIPO_TARJETA[value=CREDIT_CARD]').set(true)
237 | fill_in('TBK_NUMERO_TARJETA', with: '4051885600446623')
238 | fill_in('TBK_CVV', with: '123')
239 | shares_radio = find('input#TBK_TIPO_PAGO597020000541_noshares')
240 | expect(shares_radio).to be_checked
241 | click_button('button')
242 |
243 | # Demo Bank
244 | within_frame('transicion') do
245 | fill_in('rutClient', with: '111111111')
246 | fill_in('passwordClient', with: '123')
247 | find('input[type=submit]').click
248 |
249 | select('Rechazar', from: 'vci')
250 | find('input[type=submit]').click
251 | end
252 |
253 | # Webpay
254 | accept_alert if page.driver.options[:browser] == :firefox
255 |
256 | # Rails app
257 | expect(page).to have_content('Failed transaction')
258 | end
259 | end
260 | end
261 |
--------------------------------------------------------------------------------