wirecardmapper 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +56 -7
- data/Rakefile +14 -30
- data/lib/wirecardmapper.rb +93 -27
- data/lib/wirecardmapper/config.rb +12 -3
- data/lib/wirecardmapper/exception.rb +5 -0
- data/lib/wirecardmapper/models/base.rb +117 -0
- data/lib/wirecardmapper/models/mongo_mapper.rb +28 -0
- data/lib/wirecardmapper/railtie.rb +20 -0
- data/lib/wirecardmapper/response.rb +32 -17
- data/lib/wirecardmapper/version.rb +1 -1
- data/spec/fixtures/config/wirecardmapper.yml +12 -0
- data/spec/fixtures/create_card.xml +1 -1
- data/spec/fixtures/create_card_without_card_id.xml +34 -0
- data/spec/fixtures/get_card_info.xml +46 -0
- data/spec/fixtures/wirecard_server_down.xml +42 -0
- data/spec/functional/models/base_spec.rb +85 -0
- data/spec/functional/models/mongo_mapper_spec.rb +30 -0
- data/spec/functional/wirecardmapper_spec.rb +104 -0
- data/spec/spec_helper.rb +27 -6
- data/spec/unit/config_spec.rb +75 -0
- data/spec/unit/request_spec.rb +57 -0
- data/spec/unit/response_spec.rb +20 -7
- metadata +144 -83
- data/LICENSE +0 -20
- data/lib/wirecardmapper/net_http_monkeypatch.rb +0 -8
- data/lib/wirecardmapper/xml.rb +0 -43
- data/spec/functional/request_spec.rb +0 -58
- data/templates/change_card_status.xml +0 -7
- data/templates/create_card.xml +0 -8
- data/templates/get_card_info.xml +0 -6
- data/templates/get_payment_info.xml +0 -11
- data/templates/main.xml +0 -7
- data/templates/submit_payment.xml +0 -10
- data/templates/update_card_info.xml +0 -6
data/README.rdoc
CHANGED
@@ -2,6 +2,44 @@
|
|
2
2
|
|
3
3
|
A Ruby Object Mapper for Wirecard XML interface
|
4
4
|
|
5
|
+
== Compatibility
|
6
|
+
|
7
|
+
wirecardmapper is tested against Ruby 1.9.2 .
|
8
|
+
|
9
|
+
{<img src="http://travis-ci.org/aklaiber/wirecardmapper.png" />}[http://travis-ci.org/aklaiber/wirecardmapper]
|
10
|
+
|
11
|
+
== Install
|
12
|
+
|
13
|
+
$ gem install wirecardmapper
|
14
|
+
|
15
|
+
or add the following line to Gemfile:
|
16
|
+
|
17
|
+
gem 'wirecardmapper'
|
18
|
+
|
19
|
+
and run bundle install from your shell.
|
20
|
+
|
21
|
+
== Examples
|
22
|
+
|
23
|
+
=== Config
|
24
|
+
|
25
|
+
WirecardMapper::Config.server_uri = "https://c3-test.wirecard.com/issuer/client"
|
26
|
+
WirecardMapper::Config.server_port = 443
|
27
|
+
WirecardMapper::Config.login = "login"
|
28
|
+
WirecardMapper::Config.password = "password"
|
29
|
+
WirecardMapper::Config.mode = "live"
|
30
|
+
WirecardMapper::Config.entity_id = "entity_id"
|
31
|
+
WirecardMapper::Config.product_id = 11
|
32
|
+
|
33
|
+
=== How to use
|
34
|
+
|
35
|
+
WirecardMapper.create_card
|
36
|
+
WirecardMapper.card_info(:card_id => '47ae07020a010018157db66065da6e5c')
|
37
|
+
WirecardMapper.update_card_info(:card_id => '47ae07020a010018157db66065da6e5c')
|
38
|
+
WirecardMapper.submit_payment(:card_id => '47ae07020a010018157db66065da6e5c', :amount => 10, :payment_comment => "Test Comment")
|
39
|
+
WirecardMapper.submit_payment(:card_id => '47ae07020a010018157db66065da6e5c', :amount => -10, :payment_comment => "Test Comment")
|
40
|
+
WirecardMapper.payment_info(:card_id => '47ae07020a010018157db66065da6e5c', :from => Time.now - (24 * 3600), :to => Time.now)
|
41
|
+
WirecardMapper.change_card_status(:card_id => '47ae07020a010018157db66065da6e5c', :status_code => 'cancelled')
|
42
|
+
|
5
43
|
== Note on Patches/Pull Requests
|
6
44
|
|
7
45
|
* Fork the project.
|
@@ -10,14 +48,25 @@ A Ruby Object Mapper for Wirecard XML interface
|
|
10
48
|
* Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself in another branch so I can ignore when I pull)
|
11
49
|
* Send me a pull request. Bonus points for topic branches.
|
12
50
|
|
13
|
-
==
|
14
|
-
|
15
|
-
$ gem install wirecardmapper
|
51
|
+
== Copyright
|
16
52
|
|
17
|
-
|
53
|
+
Copyright (c) 2010 Alexander Klaiber
|
18
54
|
|
19
|
-
|
55
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
56
|
+
a copy of this software and associated documentation files (the
|
57
|
+
"Software"), to deal in the Software without restriction, including
|
58
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
59
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
60
|
+
permit persons to whom the Software is furnished to do so, subject to
|
61
|
+
the following conditions:
|
20
62
|
|
21
|
-
|
63
|
+
The above copyright notice and this permission notice shall be
|
64
|
+
included in all copies or substantial portions of the Software.
|
22
65
|
|
23
|
-
|
66
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
67
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
68
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
69
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
70
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
71
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
72
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
CHANGED
@@ -1,24 +1,21 @@
|
|
1
|
-
require '
|
2
|
-
|
3
|
-
require 'rake'
|
4
|
-
require 'rake/rdoctask'
|
5
|
-
|
1
|
+
require 'bundler'
|
6
2
|
require "rspec"
|
7
|
-
require
|
3
|
+
require 'rspec/core/rake_task'
|
8
4
|
|
9
|
-
|
5
|
+
Bundler::GemHelper.install_tasks
|
10
6
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
end
|
7
|
+
RSpec::Core::RakeTask.new(:spec)
|
8
|
+
|
9
|
+
namespace :spec do
|
10
|
+
desc "Run the code examples in spec/unit"
|
11
|
+
RSpec::Core::RakeTask.new('unit') do |t|
|
12
|
+
t.pattern = 'spec/unit/**/*_spec.rb'
|
13
|
+
end
|
19
14
|
|
20
|
-
|
21
|
-
|
15
|
+
desc "Run the code examples in spec/functional"
|
16
|
+
RSpec::Core::RakeTask.new('functional') do |t|
|
17
|
+
t.pattern = 'spec/functional/*_spec.rb'
|
18
|
+
end
|
22
19
|
end
|
23
20
|
|
24
21
|
namespace :wirecard do
|
@@ -27,16 +24,3 @@ namespace :wirecard do
|
|
27
24
|
sh "ssh test.freecent.com -L localhost:8080:c3-test.wirecard.com:443"
|
28
25
|
end
|
29
26
|
end
|
30
|
-
|
31
|
-
desc 'Builds the gem'
|
32
|
-
task :build do
|
33
|
-
sh "gem build wirecardmapper.gemspec"
|
34
|
-
end
|
35
|
-
|
36
|
-
desc 'Tags version, pushes to remote, and pushes gem'
|
37
|
-
task :release => [:spec, :build] do
|
38
|
-
sh "git tag v#{WirecardMapper::Version}"
|
39
|
-
sh "git push origin master"
|
40
|
-
sh "git push origin v#{WirecardMapper::Version}"
|
41
|
-
sh "gem push wirecardmapper-#{WirecardMapper::Version}.gem"
|
42
|
-
end
|
data/lib/wirecardmapper.rb
CHANGED
@@ -1,52 +1,111 @@
|
|
1
|
-
require "rubygems"
|
2
1
|
require "bundler/setup"
|
3
2
|
|
4
|
-
require
|
3
|
+
require "active_support/core_ext"
|
4
|
+
require "net/https"
|
5
5
|
require "base64"
|
6
|
-
require
|
7
|
-
require
|
6
|
+
require "nokogiri"
|
7
|
+
require "uuid"
|
8
|
+
require "time"
|
9
|
+
require "money"
|
8
10
|
|
9
|
-
require
|
11
|
+
require "wirecardmapper/railtie" if defined?(Rails)
|
12
|
+
require "wirecardmapper/exception"
|
13
|
+
require "wirecardmapper/config"
|
14
|
+
require "wirecardmapper/response"
|
15
|
+
|
16
|
+
require 'wirecardmapper/models/base'
|
17
|
+
require 'wirecardmapper/models/mongo_mapper'
|
10
18
|
|
11
19
|
module WirecardMapper
|
12
|
-
autoload :Config, 'wirecardmapper/config'
|
13
|
-
autoload :Xml, 'wirecardmapper/xml'
|
14
|
-
autoload :Response, 'wirecardmapper/response'
|
15
20
|
|
16
|
-
|
21
|
+
private
|
22
|
+
|
23
|
+
def self.define_request(name, options = {:default => {}})
|
24
|
+
define_singleton_method("#{name}_request") do |params = {}|
|
25
|
+
build_request(options[:request_method].blank? ? name : options[:request_method], options[:default].blank? ? params : options[:default].deep_merge(params))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
public
|
30
|
+
|
31
|
+
define_request :create_card, :default => {:product_data => {:product_id => lambda { Config.product_id }}, :card_data => nil}
|
17
32
|
|
18
33
|
def self.create_card(params = {})
|
19
|
-
|
34
|
+
self.post(self.create_card_request(params))
|
20
35
|
end
|
21
36
|
|
22
|
-
|
23
|
-
|
37
|
+
define_request :card_info, :request_method => 'get_card_info'
|
38
|
+
|
39
|
+
def self.card_info(card_id, params = {})
|
40
|
+
self.post(self.card_info_request({:card_data => {:card_id => card_id}}.deep_merge(params)))
|
41
|
+
end
|
42
|
+
|
43
|
+
define_request :update_card_info
|
44
|
+
|
45
|
+
def self.update_card_info(card_id, params = {})
|
46
|
+
self.post(self.update_card_info_request({:card_data => {:card_id => card_id}}.deep_merge(params)))
|
24
47
|
end
|
25
48
|
|
26
|
-
|
27
|
-
|
49
|
+
define_request :payment_info, :request_method => 'get_payment_info'
|
50
|
+
|
51
|
+
def self.payment_info(card_id, params = {})
|
52
|
+
self.post(self.payment_info_request(params.deep_merge(:card_data => {:card_id => card_id})))
|
28
53
|
end
|
29
54
|
|
30
|
-
|
31
|
-
|
55
|
+
define_request :change_card_status
|
56
|
+
|
57
|
+
def self.change_card_status(card_id, params = {})
|
58
|
+
self.post(self.change_card_status_request(params.deep_merge(:card_data => {:card_id => card_id})))
|
32
59
|
end
|
33
60
|
|
34
|
-
|
35
|
-
|
61
|
+
define_request :submit_payment
|
62
|
+
|
63
|
+
def self.submit_payment(card_id, params = {})
|
64
|
+
self.post(self.submit_payment_request(params.deep_merge(:card_data => {:card_id => card_id})))
|
36
65
|
end
|
37
66
|
|
38
|
-
|
39
|
-
|
67
|
+
private
|
68
|
+
|
69
|
+
def self.build_request(method, params)
|
70
|
+
builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
|
71
|
+
xml.send('issuer-request', :mode => Config.mode, :version => '1.0') do
|
72
|
+
xml.application do
|
73
|
+
xml.send('request-id', UUID.generate)
|
74
|
+
if params[:entity_id].present?
|
75
|
+
xml.send('entity-id', params[:entity_id])
|
76
|
+
params.delete(:entity_id)
|
77
|
+
else
|
78
|
+
xml.send('entity-id', Config.entity_id)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
xml.send(method.to_s.gsub(/_/, '-')) do
|
82
|
+
self.build_request_method_params(xml, params) unless params.blank?
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
builder.to_xml
|
40
87
|
end
|
41
88
|
|
42
|
-
def self.
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
89
|
+
def self.build_request_method_params(xml, params)
|
90
|
+
params.each do |key, value|
|
91
|
+
if value.kind_of?(Hash)
|
92
|
+
if value.include?(:text) || value.include?(:attributes)
|
93
|
+
xml.send(key.to_s.gsub(/_/, '-'), value[:attributes]) do
|
94
|
+
xml.text value[:text]
|
95
|
+
end
|
96
|
+
else
|
97
|
+
xml.send(key.to_s.gsub(/_/, '-')) do
|
98
|
+
self.build_request_method_params(xml, value)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
else
|
102
|
+
if value.kind_of?(Proc)
|
103
|
+
xml.send(key.to_s.gsub(/_/, '-'), value.call)
|
104
|
+
else
|
105
|
+
xml.send(key.to_s.gsub(/_/, '-'), value)
|
106
|
+
end
|
47
107
|
end
|
48
108
|
end
|
49
|
-
return post(main_xml.to_s)
|
50
109
|
end
|
51
110
|
|
52
111
|
def self.post(xml)
|
@@ -54,7 +113,9 @@ module WirecardMapper
|
|
54
113
|
unless uri.nil?
|
55
114
|
http = Net::HTTP.new(uri.host, Config.server_port)
|
56
115
|
if http
|
116
|
+
http.read_timeout = 30
|
57
117
|
http.use_ssl = true
|
118
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
58
119
|
request = Net::HTTP::Post.new(uri.path)
|
59
120
|
if request
|
60
121
|
request.content_type = "text/xml"
|
@@ -63,10 +124,15 @@ module WirecardMapper
|
|
63
124
|
request.body = xml
|
64
125
|
response = http.request(request)
|
65
126
|
if response
|
66
|
-
|
127
|
+
response = WirecardMapper::Response.new(response.body)
|
128
|
+
if response.return_message.eql?("System error.")
|
129
|
+
raise WirecardMapper::Exception, "Wirecard-System error (#{WirecardMapper::Config.server_uri}) post response : #{response.return_message}"
|
130
|
+
end
|
131
|
+
return response
|
67
132
|
end
|
68
133
|
end
|
69
134
|
end
|
70
135
|
end
|
71
136
|
end
|
137
|
+
|
72
138
|
end
|
@@ -2,10 +2,19 @@ module WirecardMapper
|
|
2
2
|
module Config
|
3
3
|
|
4
4
|
class << self
|
5
|
-
attr_accessor :mode, :entity_id, :server_uri, :login, :password, :product_id
|
5
|
+
attr_accessor :mode, :entity_id, :server_uri, :login, :password, :product_id, :currency
|
6
|
+
|
6
7
|
attr_writer :templates_path, :server_port
|
7
8
|
end
|
8
|
-
|
9
|
+
|
10
|
+
def self.config=(config)
|
11
|
+
config.each { |method, value| self.send("#{method}=", value) if self.respond_to?(method) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.config
|
15
|
+
yield self
|
16
|
+
end
|
17
|
+
|
9
18
|
def self.templates_path
|
10
19
|
@templates_path ||= "#{File.dirname(__FILE__)}/../../templates/"
|
11
20
|
end
|
@@ -13,6 +22,6 @@ module WirecardMapper
|
|
13
22
|
def self.server_port
|
14
23
|
@server_port ||= 443
|
15
24
|
end
|
16
|
-
|
25
|
+
|
17
26
|
end
|
18
27
|
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module WirecardMapper
|
2
|
+
module Model
|
3
|
+
module Base
|
4
|
+
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def product_id(product_id = nil)
|
9
|
+
if product_id.present?
|
10
|
+
@product_id = product_id
|
11
|
+
else
|
12
|
+
@product_id
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def entity_id(entity_id = nil)
|
17
|
+
if entity_id.present?
|
18
|
+
@entity_id = entity_id
|
19
|
+
else
|
20
|
+
@entity_id
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.status_writer(*args)
|
26
|
+
args.each do |arg|
|
27
|
+
define_method("#{arg}!") do
|
28
|
+
response = WirecardMapper.change_card_status(self.card_id, {:entity_id => self.class.entity_id, :status_code => arg})
|
29
|
+
unless response.blank?
|
30
|
+
reload_card_info_cache
|
31
|
+
transaction_log("change_card_status", response)
|
32
|
+
raise WirecardMapper::Exception, "Wirecard-System[ERROR]: #{response.return_message}" unless response.ok?
|
33
|
+
end
|
34
|
+
return response
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.status_reader(*args)
|
40
|
+
args.each do |arg|
|
41
|
+
define_method("#{arg}?") do
|
42
|
+
status.to_s.eql?(arg.to_s.gsub('_', '-'))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.card_attr_reader(*args)
|
48
|
+
args.each do |arg|
|
49
|
+
define_method(arg) do
|
50
|
+
card_info.send(arg)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
public
|
56
|
+
|
57
|
+
attr_accessor :card_id
|
58
|
+
|
59
|
+
status_writer :activated, :blocked, :cancelled
|
60
|
+
|
61
|
+
status_reader :activated, :activation_pending, :activation_failed
|
62
|
+
status_reader :blocked, :block_requested, :block_pending, :block_failed
|
63
|
+
status_reader :cancelled, :cancellation_requested, :cancellation_pending, :cancellation_failed
|
64
|
+
status_reader :decline, :expired, :inactive, :referral
|
65
|
+
|
66
|
+
card_attr_reader :expiration_year, :expiration_month
|
67
|
+
|
68
|
+
public
|
69
|
+
|
70
|
+
def transaction_log(method_name, response)
|
71
|
+
end
|
72
|
+
|
73
|
+
def status
|
74
|
+
card_info.status_code
|
75
|
+
end
|
76
|
+
|
77
|
+
def balance
|
78
|
+
Money.euro(card_info.balance)
|
79
|
+
end
|
80
|
+
|
81
|
+
def load_amount(amount = self.amount.cents, comment = "load")
|
82
|
+
response = WirecardMapper.submit_payment(self.card_id, {:entity_id => self.class.entity_id, :payment_data => {:amount => {:text => amount, :attributes => {:currency => Config.currency}}, :payment_comment => comment}})
|
83
|
+
unless response.blank?
|
84
|
+
reload_card_info_cache
|
85
|
+
transaction_log("submit_payment - load_amount", response)
|
86
|
+
return response.ok?
|
87
|
+
end
|
88
|
+
return false
|
89
|
+
end
|
90
|
+
|
91
|
+
def unload_amount(amount = self.balance.cents, comment = "unload")
|
92
|
+
response = WirecardMapper.submit_payment(self.card_id, {:entity_id => self.class.entity_id,:payment_data => {:amount => {:text => -amount, :attributes => {:currency => Config.currency}}, :payment_comment => comment}})
|
93
|
+
unless response.blank?
|
94
|
+
reload_card_info_cache
|
95
|
+
transaction_log("submit_payment - unload_amount", response)
|
96
|
+
return response.ok?
|
97
|
+
end
|
98
|
+
return false
|
99
|
+
end
|
100
|
+
|
101
|
+
def amount
|
102
|
+
Money.euro(@amount)
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
def card_info
|
108
|
+
@card_info ||= WirecardMapper.card_info(self.card_id, {:entity_id => self.class.entity_id, :card_activity => 'no'})
|
109
|
+
end
|
110
|
+
|
111
|
+
def reload_card_info_cache
|
112
|
+
@card_info = nil
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|