transbank-webpay 0.1.0 → 0.2.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.
- checksums.yaml +4 -4
- data/README.md +157 -1
- data/lib/generators/transbank_webpay/install/install_generator.rb +11 -0
- data/lib/generators/transbank_webpay/install/templates/transbank_webpay.rb +23 -0
- data/lib/transbank/webpay.rb +7 -2
- data/lib/transbank/webpay/api.rb +6 -0
- data/lib/transbank/webpay/configuration.rb +1 -1
- data/lib/transbank/webpay/document.rb +39 -5
- data/lib/transbank/webpay/exception_response.rb +5 -4
- data/lib/transbank/webpay/exceptions.rb +7 -0
- data/lib/transbank/webpay/helper.rb +80 -0
- data/lib/transbank/webpay/params.rb +13 -0
- data/lib/transbank/webpay/reader.rb +76 -0
- data/lib/transbank/webpay/request.rb +5 -4
- data/lib/transbank/webpay/response.rb +15 -128
- data/lib/transbank/webpay/struct.rb +6 -0
- data/lib/transbank/webpay/validations.rb +74 -0
- data/lib/transbank/webpay/version.rb +1 -1
- data/transbank-webpay.gemspec +1 -2
- metadata +12 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7a89c6199367fd33bb85f9870e52153547414ad7
|
4
|
+
data.tar.gz: 63ec216618b2de32cd2af59ff1af1af205c64a96
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 15aa8ffba7bf1e939921501bf77576b6afc889e36d07c58007748607848fdb2ea76a6628c20061ca7cce0a74674fe499d4c77aa20c15d7f0414d1c0d6eae7683
|
7
|
+
data.tar.gz: 317322dd5edcf986a54a0bdfe8814ca22482c077efd414a2bd38aa469574da93e22f5454a46a7c1b1055a438ea733ec947585dc591130efd28489d1ed0b0b512
|
data/README.md
CHANGED
@@ -1 +1,157 @@
|
|
1
|
-
#
|
1
|
+
# Transbank::Webpay
|
2
|
+
|
3
|
+
Ruby Implementation of Transbank Webpay API SOAP
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'transbank-webpay'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install transbank-webpay
|
20
|
+
|
21
|
+
Run the generator:
|
22
|
+
|
23
|
+
$ rails generate transbank_webpay:install
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
**Init Transaction**
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
response = Transbank::Webpay.init_transaction({
|
31
|
+
buy_order: 'A1234567',
|
32
|
+
session_id: '123456',
|
33
|
+
return_url: 'http://web.com/return',
|
34
|
+
final_url: 'http://web.com/finalize',
|
35
|
+
amount: 12_000
|
36
|
+
})
|
37
|
+
=> #<Transbank::Webpay::Response valid: true, #<Transbank::Webpay::Struct token="12333b5bcd772565db2cbf36e88eafcca93a95dad29dd8bd6f44d6d37345", url="https://tbk-web.com/initTransactioninitTransaction">>
|
38
|
+
response.token
|
39
|
+
=> "12333b5bcd772565db2cbf36e88eafcca93a95dad29dd8bd6f44d6d37345"
|
40
|
+
response.url
|
41
|
+
=> "https://tbk-web.com/initTransaction"
|
42
|
+
response.valid?
|
43
|
+
=> true
|
44
|
+
```
|
45
|
+
|
46
|
+
**Get Transaction Result**
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
response = Transbank::Webpay.get_transaction_result(token)
|
50
|
+
=> #<Transbank::Webpay::Response valid: true, #<Transbank::Webpay::Struct accounting_date="0234", buy_order="A1234567", card_detail=#<Transbank::Webpay::Struct card_number=3456>, detail_output=#<Transbank::Webpay::Struct shares_number=0, amount=12000, commerce_code=237020000556, buy_order="A1234567", authorization_code=1234, payment_type_code="VN", response_code=0>, session_id=123456, transaction_date=Mon, 10 Jul 2016 10:00:00 -0400, url_redirection="https://tbk-web.com/filtroUnificado/voucher.cgi", vci="TSY">>
|
51
|
+
response.accounting_date
|
52
|
+
=> "0234"
|
53
|
+
response.buy_order
|
54
|
+
=> "A1234567"
|
55
|
+
response.card_detail.card_number
|
56
|
+
=> 3456
|
57
|
+
response.detail_output.shares_number
|
58
|
+
=> 0
|
59
|
+
response.detail_output.amount
|
60
|
+
=> 12000
|
61
|
+
response.detail_output.commerce_code
|
62
|
+
=> 237020000556
|
63
|
+
response.detail_output.buy_order
|
64
|
+
=> "A1234567"
|
65
|
+
response.detail_output.authorization_code
|
66
|
+
=> 1234
|
67
|
+
response.detail_output.payment_type_code
|
68
|
+
=> "VN"
|
69
|
+
response.response_code
|
70
|
+
=> 0
|
71
|
+
response.session_id
|
72
|
+
=> 123456
|
73
|
+
response.transaction_date
|
74
|
+
=> Mon, 10 Jul 2016 10:00:00 -0400
|
75
|
+
response.url_redirection
|
76
|
+
=> "https://tbk-web.com/filtroUnificado/voucher.cgi"
|
77
|
+
response.vci
|
78
|
+
=> "TSY"
|
79
|
+
response.valid?
|
80
|
+
=> true
|
81
|
+
```
|
82
|
+
|
83
|
+
**Acknowledge Transaction**
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
response = Transbank::Webpay.acknowledge_transaction(token)
|
87
|
+
=> #< Transbank::Webpay::Response valid: true>
|
88
|
+
response.valid?
|
89
|
+
=> true
|
90
|
+
```
|
91
|
+
|
92
|
+
**Nullify**
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
Transbank::Webpay.nullify({
|
96
|
+
authorization_code: 1234,
|
97
|
+
authorized_amount: 12_000,
|
98
|
+
buy_order: 'A1234567',
|
99
|
+
nullify_amount: 12_000
|
100
|
+
})
|
101
|
+
=> #<Transbank::Webpay::Response valid: true, #<Transbank::Webpay::Struct authorization_code=1415234, authorization_date=Mon, 10 Jul 2016 10:00:00 -0400, balance=0, nullified_amount=12000, token="8743gr557f7037005a48487197b0539a021436dabaf485c4947c95347ba1dgdw78">>
|
102
|
+
|
103
|
+
response.authorization_code
|
104
|
+
=> 1415234
|
105
|
+
response.authorization_date
|
106
|
+
=> Mon, 10 Jul 2016 10:00:00 -0400
|
107
|
+
response.balance
|
108
|
+
=> 0
|
109
|
+
response.nullified_amount
|
110
|
+
=> 12000
|
111
|
+
response.token
|
112
|
+
=> "8743gr557f7037005a48487197b0539a021436dabaf485c4947c95347ba1dgdw78"
|
113
|
+
response.valid?
|
114
|
+
=> true
|
115
|
+
```
|
116
|
+
**Available response methods:**
|
117
|
+
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
response.valid? # true or false if any errors occurred (exceptions included)
|
121
|
+
response.errors # errors array
|
122
|
+
response.errors_display? # errors for human
|
123
|
+
response.exception? # true or false if an exception occurred
|
124
|
+
response.exception # exception object
|
125
|
+
response.attributes # hash attributes response (token, reverse_code . . .)
|
126
|
+
```
|
127
|
+
|
128
|
+
## Configuration
|
129
|
+
|
130
|
+
First, you need to set up your configuration:
|
131
|
+
|
132
|
+
`rails generate transbank_webpay:install`
|
133
|
+
|
134
|
+
Then edit (config/initializers/transbank_webpay.rb):
|
135
|
+
|
136
|
+
```ruby
|
137
|
+
Transbank::Webpay.configure do |config|
|
138
|
+
config.wsdl_transaction_url = 'WEBPAY_SOAP_URL'
|
139
|
+
config.wsdl_nullify_url = 'NULLIFY_WEBPAY_SOAP_URL'
|
140
|
+
config.cert_path = 'ABSOLUTE_PATH_TO_CRT_FILE'
|
141
|
+
config.key_path = 'ABSOLUTE_PATH_TO_KEY_FILE'
|
142
|
+
config.server_cert_path = 'ABSOLUTE_PATH_TO_SERVER_CRT_OR_PEM_FILE'
|
143
|
+
config.commerce_code = 'COMMERCE_CODE'
|
144
|
+
end
|
145
|
+
```
|
146
|
+
|
147
|
+
## Contributing
|
148
|
+
|
149
|
+
1. Fork it ( https://github.com/[my-github-username]/transbank-webpay/fork )
|
150
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
151
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
152
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
153
|
+
5. Create a new Pull Request
|
154
|
+
|
155
|
+
## License
|
156
|
+
|
157
|
+
transbank-webpay is released under the [MIT License](http://www.opensource.org/licenses/MIT).
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module TransbankWebpay
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
source_root File.expand_path('../templates', __FILE__)
|
5
|
+
|
6
|
+
def generate_config_file
|
7
|
+
copy_file 'transbank_webpay.rb', 'config/initializers/transbank_webpay.rb'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
Transbank::Webpay.configure do |config|
|
2
|
+
config.wsdl_transaction_url = 'WEBPAY_SOAP_URL'
|
3
|
+
config.wsdl_nullify_url = 'NULLIFY_WEBPAY_SOAP_URL'
|
4
|
+
config.cert_path = 'ABSOLUTE_PATH_TO_CRT_FILE'
|
5
|
+
config.key_path = 'ABSOLUTE_PATH_TO_KEY_FILE'
|
6
|
+
config.server_cert_path = 'ABSOLUTE_PATH_TO_SERVER_CRT_OR_PEM_FILE'
|
7
|
+
config.commerce_code = 'COMMERCE_CODE'
|
8
|
+
|
9
|
+
# These are the default options for Net::HTTP
|
10
|
+
# config.http_options = { read_timeout: 80 }
|
11
|
+
|
12
|
+
# ignores any exception passed as argument
|
13
|
+
# not capture any exception: config.rescue_exceptions []
|
14
|
+
# Default is:
|
15
|
+
# [
|
16
|
+
# Net::ReadTimeout, Timeout::Error, Errno::EINVAL, Errno::ECONNRESET,
|
17
|
+
# EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError
|
18
|
+
# ]
|
19
|
+
# config.rescue_exceptions = [
|
20
|
+
# Net::ReadTimeout, Timeout::Error,
|
21
|
+
# Transbank::Webpay::Exceptions::InvalidSignature
|
22
|
+
# ]
|
23
|
+
end
|
data/lib/transbank/webpay.rb
CHANGED
@@ -1,12 +1,17 @@
|
|
1
1
|
require 'net/https'
|
2
2
|
require 'uri'
|
3
|
-
require '
|
3
|
+
require 'nokogiri'
|
4
4
|
require 'signer'
|
5
|
-
require 'nori'
|
6
5
|
require 'ostruct'
|
6
|
+
require 'builder'
|
7
7
|
|
8
8
|
require 'transbank/webpay/version'
|
9
9
|
require 'transbank/webpay/configuration'
|
10
|
+
require 'transbank/webpay/validations'
|
11
|
+
require 'transbank/webpay/struct'
|
12
|
+
require 'transbank/webpay/reader'
|
13
|
+
require 'transbank/webpay/exceptions'
|
14
|
+
require 'transbank/webpay/helper'
|
10
15
|
require 'transbank/webpay/exception_response'
|
11
16
|
require 'transbank/webpay/client'
|
12
17
|
require 'transbank/webpay/response'
|
data/lib/transbank/webpay/api.rb
CHANGED
@@ -21,6 +21,12 @@ module Transbank
|
|
21
21
|
Request.new(url, :acknowledge_transaction, params).response
|
22
22
|
end
|
23
23
|
|
24
|
+
def nullify(underscore_params = {})
|
25
|
+
params = build_nullify_params(underscore_params)
|
26
|
+
url = config.wsdl_nullify_url
|
27
|
+
Request.new(url, :nullify, params).response
|
28
|
+
end
|
29
|
+
|
24
30
|
private
|
25
31
|
|
26
32
|
def config
|
@@ -1,15 +1,25 @@
|
|
1
1
|
module Transbank
|
2
2
|
module Webpay
|
3
3
|
class Document
|
4
|
-
|
4
|
+
include Helper
|
5
|
+
attr_reader :unsigned_xml
|
5
6
|
XML_HEADER = "<env:Header><wsse:Security xmlns:wsse='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' wsse:mustUnderstand='1'/></env:Header>".freeze # rubocop:disable LineLength
|
6
7
|
SOAPENV = 'http://schemas.xmlsoap.org/soap/envelope/'.freeze
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
9
|
+
NAMESPACES = {
|
10
|
+
'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema',
|
11
|
+
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
|
12
|
+
'xmlns:tns' => 'http://service.wswebpay.webpay.transbank.com/',
|
13
|
+
'xmlns:env' => 'http://schemas.xmlsoap.org/soap/envelope/'
|
14
|
+
}.freeze
|
11
15
|
|
12
|
-
|
16
|
+
def initialize(action, params = {})
|
17
|
+
camelcase_action = camelcase(action).to_sym
|
18
|
+
@unsigned_xml = build_xml camelcase_action, params
|
19
|
+
end
|
20
|
+
|
21
|
+
def unsigned_document
|
22
|
+
@unsigned_document ||= Nokogiri::XML(unsigned_xml)
|
13
23
|
end
|
14
24
|
|
15
25
|
def envelope
|
@@ -47,6 +57,30 @@ module Transbank
|
|
47
57
|
signer.to_xml
|
48
58
|
end
|
49
59
|
|
60
|
+
private
|
61
|
+
|
62
|
+
def build_xml(action, params = {})
|
63
|
+
xml = Builder::XmlMarkup.new indent: 0
|
64
|
+
xml.instruct! :xml, encoding: 'UTF-8'
|
65
|
+
xml.env(:Envelope, NAMESPACES) do
|
66
|
+
xml.env(:Body) do
|
67
|
+
xml.tns(action) do
|
68
|
+
params.each do |name, value|
|
69
|
+
build_tag(xml, name, value)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def build_tag(xml, name, value)
|
77
|
+
return xml.tag!(name, value) unless value.is_a?(Hash)
|
78
|
+
|
79
|
+
xml.tag!(name) do
|
80
|
+
value.each { |k, v| build_tag(xml, k, v) }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
50
84
|
def cert
|
51
85
|
@cert ||= OpenSSL::X509::Certificate.new open(Transbank::Webpay.configuration.cert_path)
|
52
86
|
end
|
@@ -1,11 +1,12 @@
|
|
1
1
|
module Transbank
|
2
2
|
module Webpay
|
3
3
|
class ExceptionResponse
|
4
|
-
|
4
|
+
attr_reader :exception, :action, :params
|
5
5
|
|
6
|
-
def initialize(exception, action)
|
7
|
-
|
8
|
-
|
6
|
+
def initialize(exception, action, params)
|
7
|
+
@exception = exception
|
8
|
+
@action = action
|
9
|
+
@params = params
|
9
10
|
end
|
10
11
|
|
11
12
|
def valid?
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Transbank
|
2
|
+
module Webpay
|
3
|
+
module Helper
|
4
|
+
XS_INTEGER = /^[-+]?[1-9]([0-9]*)?$|^0$/
|
5
|
+
XS_DATE_TIME = /^-?\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?$/
|
6
|
+
|
7
|
+
def camelcase(underscore)
|
8
|
+
underscore
|
9
|
+
.to_s
|
10
|
+
.gsub(/(?<=_)(\w)/) { Regexp.last_match[1].upcase }
|
11
|
+
.gsub(/(?:_)(\w)/, '\1')
|
12
|
+
end
|
13
|
+
|
14
|
+
def underscore(camelcase)
|
15
|
+
camelcase
|
16
|
+
.to_s
|
17
|
+
.gsub(/::/, '/')
|
18
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
19
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
20
|
+
.tr("-", "_")
|
21
|
+
.downcase
|
22
|
+
end
|
23
|
+
|
24
|
+
def typecasting(value)
|
25
|
+
case value
|
26
|
+
when 'true'
|
27
|
+
true
|
28
|
+
when 'false'
|
29
|
+
false
|
30
|
+
when XS_DATE_TIME
|
31
|
+
try_to_convert(value) { |v| DateTime.parse(v) }
|
32
|
+
when XS_INTEGER
|
33
|
+
try_to_convert(value) { |v| Integer v }
|
34
|
+
else
|
35
|
+
value
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def xml_to_hash(xml_io)
|
40
|
+
result = Nokogiri::XML(xml_io)
|
41
|
+
xml_node_to_hash(result.root)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def xml_node_to_hash(node)
|
47
|
+
return Transbank::Webpay::Struct.new if node.nil?
|
48
|
+
return node.content unless node.element?
|
49
|
+
return if node.children.empty?
|
50
|
+
|
51
|
+
hash = node.children.each_with_object({}) do |child, h|
|
52
|
+
result = xml_node_to_hash(child)
|
53
|
+
return result if return_result?(child)
|
54
|
+
|
55
|
+
assin_values h, result, child
|
56
|
+
end
|
57
|
+
|
58
|
+
Transbank::Webpay::Struct.new hash
|
59
|
+
end
|
60
|
+
|
61
|
+
def return_result?(child)
|
62
|
+
child.next_sibling.nil? && child.previous_sibling.nil?
|
63
|
+
end
|
64
|
+
|
65
|
+
def try_to_convert(value)
|
66
|
+
yield value
|
67
|
+
rescue ArgumentError
|
68
|
+
value
|
69
|
+
end
|
70
|
+
|
71
|
+
def assin_values(hash, result, child)
|
72
|
+
return if child.name == 'text'
|
73
|
+
|
74
|
+
key = underscore child.name
|
75
|
+
value = typecasting result
|
76
|
+
hash.store key, value
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module Transbank
|
2
2
|
module Webpay
|
3
3
|
module Params
|
4
|
+
include Helper
|
5
|
+
|
4
6
|
def build_init_transaction_params(underscore_params = {})
|
5
7
|
camelcase_params = {
|
6
8
|
wSTransactionType: 'TR_NORMAL_WS',
|
@@ -17,6 +19,17 @@ module Transbank
|
|
17
19
|
|
18
20
|
{ wsInitTransactionInput: camelcase_params }
|
19
21
|
end
|
22
|
+
|
23
|
+
def build_nullify_params(underscore_params = {})
|
24
|
+
camelcase_params = underscore_params.each_with_object({}) do |(key, value), hash|
|
25
|
+
new_key = camelcase(key).to_sym
|
26
|
+
hash[new_key] = value
|
27
|
+
end
|
28
|
+
|
29
|
+
camelcase_params[:commerceId] = Transbank::Webpay.configuration.commerce_code
|
30
|
+
|
31
|
+
{ nullificationInput: camelcase_params }
|
32
|
+
end
|
20
33
|
end
|
21
34
|
end
|
22
35
|
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Transbank
|
3
|
+
module Webpay
|
4
|
+
module Reader
|
5
|
+
attr_reader :content, :action
|
6
|
+
|
7
|
+
RESPONSE_CODE = {
|
8
|
+
get_transaction_result: {
|
9
|
+
'0' => 'transacción aprobada',
|
10
|
+
'-1' => 'rechazo de transacción',
|
11
|
+
'-2' => 'transacción debe reintentarse',
|
12
|
+
'-3' => 'error en transacción',
|
13
|
+
'-4' => 'rechazo de transacción',
|
14
|
+
'-5' => 'rechazo por error de tasa',
|
15
|
+
'-6' => 'excede cupo máximo mensual',
|
16
|
+
'-7' => 'excede límite diario por transacción',
|
17
|
+
'-8' => 'rubro no autorizado'
|
18
|
+
},
|
19
|
+
default: {
|
20
|
+
'0' => 'aprobada',
|
21
|
+
'-98' => 'Error'
|
22
|
+
}
|
23
|
+
}.freeze
|
24
|
+
|
25
|
+
def doc
|
26
|
+
@doc ||= Nokogiri::XML body
|
27
|
+
end
|
28
|
+
|
29
|
+
def response_code_display
|
30
|
+
RESPONSE_CODE.fetch(action, RESPONSE_CODE[:default]).fetch(response_code, response_code)
|
31
|
+
end
|
32
|
+
|
33
|
+
def body
|
34
|
+
content.body
|
35
|
+
end
|
36
|
+
|
37
|
+
def xml_error_display
|
38
|
+
xml_error.map { |e| e.text.gsub(/<!--|-->/, '').strip }
|
39
|
+
end
|
40
|
+
|
41
|
+
def attributes?
|
42
|
+
xml_return != ""
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def xml_return
|
48
|
+
@xml_return ||= doc.at_xpath("//return").to_s
|
49
|
+
end
|
50
|
+
|
51
|
+
def signature_decode
|
52
|
+
Base64.decode64(signature_node.content)
|
53
|
+
end
|
54
|
+
|
55
|
+
def xml_error
|
56
|
+
doc.xpath("//faultstring")
|
57
|
+
end
|
58
|
+
|
59
|
+
def response_code
|
60
|
+
doc.xpath("//responseCode").text
|
61
|
+
end
|
62
|
+
|
63
|
+
def signature_node
|
64
|
+
doc.at_xpath('//ds:SignatureValue', ds: 'http://www.w3.org/2000/09/xmldsig#')
|
65
|
+
end
|
66
|
+
|
67
|
+
def digest
|
68
|
+
doc.at_xpath("//ds:DigestValue", ds: 'http://www.w3.org/2000/09/xmldsig#').text
|
69
|
+
end
|
70
|
+
|
71
|
+
def signed_node
|
72
|
+
doc.at_xpath '//ds:SignedInfo', ds: 'http://www.w3.org/2000/09/xmldsig#'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -1,11 +1,12 @@
|
|
1
1
|
module Transbank
|
2
2
|
module Webpay
|
3
3
|
class Request
|
4
|
-
attr_accessor :client, :document, :action
|
4
|
+
attr_accessor :client, :document, :action, :params
|
5
5
|
|
6
6
|
def initialize(wsdl_url, action, params = {})
|
7
|
+
@params = params
|
7
8
|
@action = action
|
8
|
-
@document = Document.new(
|
9
|
+
@document = Document.new(action, params)
|
9
10
|
@client = Client.new wsdl_url
|
10
11
|
end
|
11
12
|
|
@@ -13,9 +14,9 @@ module Transbank
|
|
13
14
|
rescue_exceptions = Transbank::Webpay.configuration.rescue_exceptions
|
14
15
|
|
15
16
|
@response ||= begin
|
16
|
-
Response.new client.post(document.to_xml), action
|
17
|
+
Response.new client.post(document.to_xml), action, params
|
17
18
|
rescue match_class(rescue_exceptions) => error
|
18
|
-
ExceptionResponse.new error, action
|
19
|
+
ExceptionResponse.new error, action, params
|
19
20
|
end
|
20
21
|
end
|
21
22
|
|
@@ -1,94 +1,31 @@
|
|
1
|
-
# rubocop:disable all
|
2
1
|
module Transbank
|
3
2
|
module Webpay
|
4
3
|
class Response
|
5
|
-
|
4
|
+
include Validations
|
5
|
+
include Reader
|
6
|
+
include Helper
|
6
7
|
|
7
|
-
|
8
|
-
get_transaction_result: {
|
9
|
-
'0' => 'transacción aprobada',
|
10
|
-
'-1' => 'rechazo de transacción',
|
11
|
-
'-2' => 'transacción debe reintentarse',
|
12
|
-
'-3' => 'error en transacción',
|
13
|
-
'-4' => 'rechazo de transacción',
|
14
|
-
'-5' => 'rechazo por error de tasa',
|
15
|
-
'-6' => 'excede cupo máximo mensual',
|
16
|
-
'-7' => 'excede límite diario por transacción',
|
17
|
-
'-8' => 'rubro no autorizado'
|
18
|
-
},
|
19
|
-
default: {
|
20
|
-
'0' => 'aprobado',
|
21
|
-
'-98' => 'Error'
|
22
|
-
}
|
23
|
-
}
|
8
|
+
attr_reader :attributes, :exception, :params
|
24
9
|
|
25
|
-
def initialize(content, action)
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
end
|
10
|
+
def initialize(content, action, params)
|
11
|
+
@content = content
|
12
|
+
@action = action
|
13
|
+
@params = params
|
14
|
+
@attributes = xml_to_hash(xml_return)
|
15
|
+
@errors = []
|
32
16
|
|
33
|
-
|
34
|
-
content.body
|
17
|
+
validate_response!
|
35
18
|
end
|
36
19
|
|
37
20
|
def http_code
|
38
21
|
content.code
|
39
22
|
end
|
40
23
|
|
41
|
-
def doc
|
42
|
-
@doc ||= Nokogiri::XML body
|
43
|
-
end
|
44
|
-
|
45
|
-
def xml_result
|
46
|
-
parser.parse(doc.at_xpath("//return").to_s).fetch( :return, {}).tap do |hash|
|
47
|
-
hash[:detail_output].tap {|r| r[:amount] = r[:amount].to_i }
|
48
|
-
|
49
|
-
hash.each { |k, v| hash.store(k, OpenStruct.new(v)) if v.is_a?(Hash) }
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def xml_error
|
54
|
-
doc.xpath("//faultstring")
|
55
|
-
end
|
56
|
-
|
57
|
-
def errors_display
|
58
|
-
errors.join ', '
|
59
|
-
end
|
60
|
-
|
61
|
-
def valid?
|
62
|
-
errors.empty?
|
63
|
-
end
|
64
|
-
|
65
|
-
def signed_node
|
66
|
-
doc.at_xpath '//ds:SignedInfo', {'ds' => 'http://www.w3.org/2000/09/xmldsig#'}
|
67
|
-
end
|
68
|
-
|
69
|
-
def signature_node
|
70
|
-
doc.at_xpath('//ds:SignatureValue', {'ds' => 'http://www.w3.org/2000/09/xmldsig#'})
|
71
|
-
end
|
72
|
-
|
73
|
-
def signature_decode
|
74
|
-
Base64.decode64(signature_node.content)
|
75
|
-
end
|
76
|
-
|
77
|
-
def response_code
|
78
|
-
@response_code ||= doc.xpath("//responseCode").text
|
79
|
-
end
|
80
|
-
|
81
|
-
def response_code_display
|
82
|
-
if response_code.present?
|
83
|
-
RESPONSE_CODE.fetch(action, RESPONSE_CODE[:default]).fetch(response_code, response_code)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
24
|
def inspect
|
88
25
|
result = ["valid: #{valid?}"]
|
89
|
-
result <<
|
26
|
+
result << attributes.inspect if attributes?
|
90
27
|
result << "error: \"#{errors_display}\"" if errors.any?
|
91
|
-
"#<#{self.class} #{result.join(', ')}
|
28
|
+
"#<#{self.class} #{result.join(', ')}>"
|
92
29
|
end
|
93
30
|
|
94
31
|
def exception?
|
@@ -100,62 +37,12 @@ module Transbank
|
|
100
37
|
end
|
101
38
|
|
102
39
|
def method_missing(method_name, *args, &block)
|
103
|
-
attributes
|
40
|
+
attributes.respond_to?(method_name) && attributes.send(method_name) || super
|
104
41
|
end
|
105
42
|
|
106
43
|
def respond_to_missing?(method_name, include_private = false)
|
107
|
-
attributes.
|
108
|
-
end
|
109
|
-
|
110
|
-
def xml_error_display
|
111
|
-
xml_error.map { |e| e.text.gsub(/<!--|-->/, '').strip }
|
112
|
-
end
|
113
|
-
|
114
|
-
private
|
115
|
-
|
116
|
-
def verify
|
117
|
-
return if signature_node.nil?
|
118
|
-
|
119
|
-
signed_node.add_namespace 'soap', 'http://schemas.xmlsoap.org/soap/envelope/'
|
120
|
-
signed_node_canonicalize = signed_node.canonicalize Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0, ["soap"], nil
|
121
|
-
|
122
|
-
pub_key.verify OpenSSL::Digest::SHA1.new, signature_decode, signed_node_canonicalize
|
123
|
-
end
|
124
|
-
|
125
|
-
def server_cert
|
126
|
-
@server_cert ||= begin
|
127
|
-
path = Transbank::Webpay.configuration.server_cert_path
|
128
|
-
OpenSSL::X509::Certificate.new File.read(path)
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
def pub_key
|
133
|
-
server_cert.public_key
|
134
|
-
end
|
135
|
-
|
136
|
-
def parser
|
137
|
-
@parser ||= Nori.new convert_tags_to: lambda { |tag| tag.snakecase.to_sym }
|
138
|
-
end
|
139
|
-
|
140
|
-
def attributes_display
|
141
|
-
attributes.map{|name, value| "#{name}: \"#{value}\""}.join ', '
|
142
|
-
end
|
143
|
-
|
144
|
-
def validate!
|
145
|
-
if response_code.present? and response_code != '0'
|
146
|
-
self.errors << response_code_display
|
147
|
-
end
|
148
|
-
|
149
|
-
if content.class != Net::HTTPOK
|
150
|
-
self.errors += xml_error_display
|
151
|
-
self.errors << content.message if content.respond_to?(:message) and self.errors.blank?
|
152
|
-
end
|
153
|
-
|
154
|
-
if (self.errors.blank? || signature_node.present?) && !verify
|
155
|
-
raise Exceptions::InvalidSignature.new("Invalid signature")
|
156
|
-
end
|
44
|
+
attributes.respond_to?(method_name, include_private) || super
|
157
45
|
end
|
158
46
|
end
|
159
47
|
end
|
160
48
|
end
|
161
|
-
# rubocop:enable all
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Transbank
|
2
|
+
module Webpay
|
3
|
+
module Validations
|
4
|
+
attr_reader :errors
|
5
|
+
|
6
|
+
def errors_display
|
7
|
+
errors.join ', '
|
8
|
+
end
|
9
|
+
|
10
|
+
def valid?
|
11
|
+
errors.empty?
|
12
|
+
end
|
13
|
+
|
14
|
+
def validate_response!
|
15
|
+
validate_response_code!
|
16
|
+
validate_http_response!
|
17
|
+
|
18
|
+
return if errors.any? || validate_document
|
19
|
+
|
20
|
+
raise Transbank::Webpay::Exceptions::InvalidSignature, 'Invalid signature'
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def calculated_digest
|
26
|
+
node = doc.at_xpath('//soap:Body')
|
27
|
+
node_canonicalize = node.canonicalize(Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0, nil, nil)
|
28
|
+
digest = OpenSSL::Digest::SHA1.new.reset.digest(node_canonicalize)
|
29
|
+
Base64.encode64(digest).strip
|
30
|
+
end
|
31
|
+
|
32
|
+
def server_cert
|
33
|
+
@server_cert ||= begin
|
34
|
+
path = Transbank::Webpay.configuration.server_cert_path
|
35
|
+
OpenSSL::X509::Certificate.new File.read(path)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def pub_key
|
40
|
+
server_cert.public_key
|
41
|
+
end
|
42
|
+
|
43
|
+
# Validations
|
44
|
+
def validate_response_code!
|
45
|
+
return if response_code.empty?
|
46
|
+
@errors << response_code_display if response_code != '0'
|
47
|
+
end
|
48
|
+
|
49
|
+
def validate_http_response!
|
50
|
+
return if content.class == Net::HTTPOK
|
51
|
+
|
52
|
+
@errors += xml_error_display
|
53
|
+
@errors << content.message if content.respond_to?(:message) && @errors.empty?
|
54
|
+
end
|
55
|
+
|
56
|
+
def validate_document
|
57
|
+
return false if signature_node.nil?
|
58
|
+
validate_digest && validate_signature
|
59
|
+
end
|
60
|
+
|
61
|
+
def validate_signature
|
62
|
+
signed_node_canonicalize = signed_node.canonicalize(
|
63
|
+
Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0, ["soap"], nil
|
64
|
+
)
|
65
|
+
|
66
|
+
pub_key.verify OpenSSL::Digest::SHA1.new, signature_decode, signed_node_canonicalize
|
67
|
+
end
|
68
|
+
|
69
|
+
def validate_digest
|
70
|
+
calculated_digest == digest
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/transbank-webpay.gemspec
CHANGED
@@ -20,9 +20,8 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
22
|
spec.add_dependency 'signer'
|
23
|
-
spec.add_dependency 'savon', '~> 2.0'
|
24
23
|
spec.add_dependency 'nokogiri'
|
25
|
-
spec.add_dependency '
|
24
|
+
spec.add_dependency 'builder', '>= 2.0'
|
26
25
|
|
27
26
|
spec.add_development_dependency 'bundler', '~> 1.11'
|
28
27
|
spec.add_development_dependency 'rake', '~> 10.0'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: transbank-webpay
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ramón Soto
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-07-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: signer
|
@@ -24,20 +24,6 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: savon
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - "~>"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '2.0'
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - "~>"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '2.0'
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
28
|
name: nokogiri
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -53,19 +39,19 @@ dependencies:
|
|
53
39
|
- !ruby/object:Gem::Version
|
54
40
|
version: '0'
|
55
41
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
42
|
+
name: builder
|
57
43
|
requirement: !ruby/object:Gem::Requirement
|
58
44
|
requirements:
|
59
45
|
- - ">="
|
60
46
|
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
47
|
+
version: '2.0'
|
62
48
|
type: :runtime
|
63
49
|
prerelease: false
|
64
50
|
version_requirements: !ruby/object:Gem::Requirement
|
65
51
|
requirements:
|
66
52
|
- - ">="
|
67
53
|
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
54
|
+
version: '2.0'
|
69
55
|
- !ruby/object:Gem::Dependency
|
70
56
|
name: bundler
|
71
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -139,6 +125,8 @@ files:
|
|
139
125
|
- Rakefile
|
140
126
|
- bin/console
|
141
127
|
- bin/setup
|
128
|
+
- lib/generators/transbank_webpay/install/install_generator.rb
|
129
|
+
- lib/generators/transbank_webpay/install/templates/transbank_webpay.rb
|
142
130
|
- lib/transbank-webpay.rb
|
143
131
|
- lib/transbank/webpay.rb
|
144
132
|
- lib/transbank/webpay/api.rb
|
@@ -146,9 +134,14 @@ files:
|
|
146
134
|
- lib/transbank/webpay/configuration.rb
|
147
135
|
- lib/transbank/webpay/document.rb
|
148
136
|
- lib/transbank/webpay/exception_response.rb
|
137
|
+
- lib/transbank/webpay/exceptions.rb
|
138
|
+
- lib/transbank/webpay/helper.rb
|
149
139
|
- lib/transbank/webpay/params.rb
|
140
|
+
- lib/transbank/webpay/reader.rb
|
150
141
|
- lib/transbank/webpay/request.rb
|
151
142
|
- lib/transbank/webpay/response.rb
|
143
|
+
- lib/transbank/webpay/struct.rb
|
144
|
+
- lib/transbank/webpay/validations.rb
|
152
145
|
- lib/transbank/webpay/version.rb
|
153
146
|
- transbank-webpay.gemspec
|
154
147
|
homepage: ''
|