barzahlen 1.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d22d4228515d62a086a459066ed7d35a5fa596fb
4
+ data.tar.gz: add4528a9bb87a690c17609c81831f384bc9a06c
5
+ SHA512:
6
+ metadata.gz: bf406f3231504cd7c6047a5df34e3f4253d1a79e4a730323cfd92718f54b7380a9fb8cc90624f37d3d28c2d74a3a727a12a347978a968e1401597caefae24854
7
+ data.tar.gz: 5f9ca948df4a0fdb4c032eaf11271b61456b0c89008d7bce56b2bac805b49ebb10f9f7ecf3bf33897bdbfecd3bb9e44a96ddc50a46ff61b4f1c81f80d87b57a3
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,207 @@
1
+ # Barzahlen Ruby-SDK
2
+
3
+ The official Ruby-SDK for accessing the Barzalen Payment Service.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'barzahlen-sdk'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install barzahlen-sdk
18
+
19
+ ## Usage
20
+
21
+ ```Ruby
22
+ require 'barzahlen/api/online'
23
+ ```
24
+
25
+ ### Configuration
26
+
27
+ The configuration is a hash where :shop_id, :payment_key and :notification_key are required. For
28
+ using the sandbox you can set the :host to 'api-sandbox.barzahlen.de'.
29
+
30
+ ```Ruby
31
+ Barzahlen::Api::Online.config = {:shop_id => 'xxx',
32
+ :payment_key => 'xxx',
33
+ :notification_key => 'xxx',
34
+ :host => 'api-sandbox.barzahlen.de',}
35
+ ```
36
+
37
+ The credentials, which are necessary to handle payments with Barzahlen, can be received at
38
+ https://partner.barzahlen.de. After a successful registration a shop ID is assigned to you as
39
+ well as a payment and a notification key. Furthermore you can set your callback URL which is used
40
+ to send updates on payment and refund transactions.
41
+
42
+ ### Send requests
43
+
44
+ After you set the config you can create the transaction-api object with the method
45
+ Barzahlen::Api::Online.new_transaction_api.
46
+
47
+ If there are any errors, a RuntimeError is thrown.
48
+
49
+ #### Create transactions
50
+
51
+ ```Ruby
52
+ transaction = {
53
+ :customer_email => 'barzahlen@example.com',
54
+ :amount => '13.37',
55
+ :currency => 'EUR',
56
+ :order_id => '123', #optional
57
+ :customer_street_nr => 'Wallstr. 14a',
58
+ :customer_zipcode => '10179',
59
+ :customer_city => 'Berlin',
60
+ :customer_country => 'DE',
61
+ :customer_custom_var_0 => 'customer_custom_var_0', #optional
62
+ :customer_custom_var_1 => 'customer_custom_var_1', #optional
63
+ :customer_custom_var_2 => 'customer_custom_var_2', #optional
64
+ :language => 'de',
65
+ }
66
+ api_transaction = Barzahlen::Api::Online.new_transaction_api
67
+ response = api_transaction.create transaction
68
+ # Response contains :transaction_id, :payment_slip_link, :expiration_notice, :infotext1,
69
+ # :infotext2, :result, :hash
70
+ ```
71
+
72
+ #### Update order-id of a transaction
73
+
74
+ ```Ruby
75
+ transaction_id = 123
76
+ order_id = 456
77
+ api_transaction = Barzahlen::Api::Online.new_transaction_api
78
+ response = api_transaction.update_order_id transaction_id, order_id
79
+ # Response contains :transaction_id, :result, :hash
80
+ ```
81
+
82
+ #### Resend E-Mail for a transaction
83
+
84
+ ```Ruby
85
+ transaction_id = 123
86
+ language = 'de'
87
+ api_transaction = Barzahlen::Api::Online.new_transaction_api
88
+ response = api_transaction.resend_email transaction_id, language
89
+ # Response contains :transaction_id, :result, :hash
90
+ ```
91
+
92
+ #### Cancel a transaction
93
+
94
+ ```Ruby
95
+ transaction_id = 123
96
+ language = 'de'
97
+ api_transaction = Barzahlen::Api::Online.new_transaction_api
98
+ response = api_transaction.cancel transaction_id, language
99
+ # Response contains :transaction_id, :result, :hash
100
+ ```
101
+
102
+ #### Create a refund for a transaction
103
+
104
+ ```Ruby
105
+ transaction_id = 123
106
+ amount = '1.23'
107
+ currency = 'EUR'
108
+ language = 'de'
109
+ api_transaction = Barzahlen::Api::Online.new_transaction_api
110
+ response = api_transaction.refund transaction_id, amount, currency, language
111
+ # Response contains :origin_transaction_id, :refund_transaction_id, :result, :hash
112
+ ```
113
+
114
+ ### Handle notifications
115
+
116
+ After you set the config you can create the notification-handler object with the method
117
+ Barzahlen::Api::Online.new_notification_handler.
118
+
119
+ #### Handle a transaction-paid notification
120
+
121
+ ```Ruby
122
+ notification_handler = Barzahlen::Api::Online.new_notification_handler
123
+ notification = notification_handler.validate_request(request_parameters)
124
+ # Notification contains :state, :transaction_id, :shop_id, :customer_email, :amount, :currency,
125
+ # :notification_key and, if set while request, :order_id, :custom_var_0, :custom_var_1, :custom_var_2
126
+ if notification[:state] == Barzahlen::Api::Online::NotificationHandler::TRANSACTION_PAID
127
+ # ...
128
+ end
129
+ ```
130
+
131
+ #### Handle a transaction-expired notification
132
+
133
+ ```Ruby
134
+ notification_handler = Barzahlen::Api::Online.new_notification_handler
135
+ notification = notification_handler.validate_request(request_parameters)
136
+ # Notification contains :state, :transaction_id, :shop_id, :customer_email, :amount, :currency,
137
+ # :notification_key and, if set while request, :order_id, :custom_var_0, :custom_var_1, :custom_var_2
138
+ if notification[:state] == Barzahlen::Api::Online::NotificationHandler::TRANSACTION_EXPIRED
139
+ # ...
140
+ end
141
+ ```
142
+
143
+ #### Handle a refund-completed notification
144
+
145
+ ```Ruby
146
+ notification_handler = Barzahlen::Api::Online.new_notification_handler
147
+ notification = notification_handler.validate_request(request_parameters)
148
+ # Notification contains :state, :refund_transaction_id, :origin_transaction_id, :shop_id,
149
+ #:customer_email, :amount, :currency, :notification_key and, if set while request, :origin_order_id,
150
+ #:custom_var_0, :custom_var_1, :custom_var_2
151
+ if notification[:state] == Barzahlen::Api::Online::NotificationHandler::REFUND_COMPLETED
152
+ # ...
153
+ end
154
+ ```
155
+
156
+ #### Handle a refund-expired notification
157
+
158
+ ```Ruby
159
+ notification_handler = Barzahlen::Api::Online.new_notification_handler
160
+ notification = notification_handler.validate_request(request_parameters)
161
+ # Notification contains :state, :refund_transaction_id, :origin_transaction_id, :shop_id,
162
+ #:customer_email, :amount, :currency, :notification_key and, if set while request, :origin_order_id,
163
+ #:custom_var_0, :custom_var_1, :custom_var_2
164
+ if notification[:state] == Barzahlen::Api::Online::NotificationHandler::REFUND_EXPIRED
165
+ # ...
166
+ end
167
+ ```
168
+
169
+ ### Logging
170
+
171
+ If you want to log all requests to the API and the raw responses, you have to implement your own
172
+ http_client. As you can see this is not as hard is sounds.
173
+
174
+ ```Ruby
175
+ class LoggingClient < Barzahlen::Api::Online::Http
176
+ def request(url, parameters)
177
+ response = super
178
+
179
+ puts url
180
+ puts parameters
181
+ puts response
182
+
183
+ response
184
+ end
185
+ end
186
+
187
+ config = {:shop_id => '13446',
188
+ :payment_key => '1c7439cda8256d9ead6602087462f0e478e3f2f4',
189
+ :notification_key => '390447f4a799dcae93d62bcd9567c1795188154b',
190
+ :host => 'api-sandbox.barzahlen.de',}
191
+
192
+ http = LoggingClient.new
193
+ Barzahlen::Api::Online.api = Barzahlen::Api::Online::Api.new http, config
194
+
195
+ transaction_id = 123
196
+ order_id = 456
197
+ api_transaction = Barzahlen::Api::Online.new_transaction_api
198
+ response = api_transaction.update_order_id transaction_id, order_id
199
+ ```
200
+
201
+ ## Contributing
202
+
203
+ 1. Fork it ( http://github.com/barzahlen/Barzahlen-Ruby/fork )
204
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
205
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
206
+ 4. Push to the branch (`git push origin my-new-feature`)
207
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ # coding: utf-8
2
+
3
+ require 'bundler/gem_tasks'
data/bin/test.rb ADDED
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby_executable_hooks
2
+ # coding: utf-8
3
+
4
+ $:.unshift '/home/mathiashertlein/Development/sdk/ruby_sdk/lib'
5
+ require 'barzahlen/api/online'
6
+
7
+ class LoggingClient < Barzahlen::Api::Online::Http
8
+ def request(url, parameters)
9
+ response = super
10
+
11
+ puts url
12
+ puts parameters
13
+ puts response
14
+
15
+ response
16
+ end
17
+ end
18
+
19
+ config = {:shop_id => '13446',
20
+ :payment_key => '1c7439cda8256d9ead6602087462f0e478e3f2f4',
21
+ :notification_key => '390447f4a799dcae93d62bcd9567c1795188154b',
22
+ :host => 'api-sandbox.barzahlen.de',}
23
+
24
+ http = LoggingClient.new
25
+ Barzahlen::Api::Online.api = Barzahlen::Api::Online::Api.new http, config
26
+
27
+ transaction_id = 123
28
+ order_id = 456
29
+ Barzahlen::Api::Online.new_transaction_api
30
+ response = api_transaction.update_order_id transaction_id, order_id
@@ -0,0 +1,67 @@
1
+ # coding: utf-8
2
+
3
+ require 'openssl'
4
+ require 'net/http'
5
+
6
+ require 'barzahlen/api/online/hash_builder'
7
+ require 'barzahlen/api/online/response_parser'
8
+
9
+ module Barzahlen
10
+ module Api
11
+ module Online
12
+
13
+ # Is responsible for assemble requests and send them via https to the Barzahlen API. It can
14
+ # send requests or just build and return the hash.
15
+ class Api
16
+ def initialize(http, config)
17
+ @http = http
18
+ @config = config
19
+ end
20
+
21
+ # Assembles and sends Request to the Barzahlen API, and returns the parsed response
22
+ # path is the url path.
23
+ # key_name is the name of the config field, that contains the secret key.
24
+ # parameters_order is the order of the parameters, in which they are concatenated for
25
+ # hash building.
26
+ # parameters contains the parameters of the request.
27
+ def request(path, key_name, parameters_order, parameters)
28
+ request_url = build_url path
29
+ request_parameters = build_parameters key_name, parameters_order, parameters
30
+
31
+ response = @http.request request_url, request_parameters
32
+ parsed_response = ResponseParser.parse response.body
33
+
34
+ if response.code != '200'
35
+ raise RuntimeError, 'Barzahlen-API returned http-status: ' + response.code.to_s + ',' +
36
+ 'error-message: ' + parsed_response[:error_message] + ',' +
37
+ 'error-code: ' + parsed_response[:result]
38
+ end
39
+
40
+ parsed_response
41
+ end
42
+
43
+ # Calculates hash from passed parameters.
44
+ #
45
+ # key_name is the name of the config field, that contains the secret key.
46
+ # parameters_order is the order of the parameters, in which they are concatenated.
47
+ # parameters contains the parameters of the request.
48
+ def build_hash(key_name, parameters_order, parameters)
49
+ request_parameters = parameters.merge :shop_id => @config[:shop_id]
50
+
51
+ hash_builder = HashBuilder.new parameters_order, key_name
52
+ hash_builder.build_hash @config[key_name], request_parameters
53
+ end
54
+
55
+ private
56
+ def build_url(path)
57
+ URI('https://' + @config[:host] + '/' + path)
58
+ end
59
+
60
+ def build_parameters(key_name, parameters_order, parameters)
61
+ hash = build_hash key_name, parameters_order, parameters
62
+ parameters.merge :shop_id => @config[:shop_id], :hash => hash
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,43 @@
1
+ # coding: utf-8
2
+
3
+ require 'digest/sha2'
4
+
5
+ module Barzahlen
6
+ module Api
7
+ module Online
8
+
9
+ # Creates hashes from a set of parameters with th following algorithm:
10
+ # SHA512(param1;param2;param3;key)
11
+ class HashBuilder
12
+ def initialize(parameters_order, key_parameter_name)
13
+ @parameters_order = parameters_order
14
+ @key_parameter_name = key_parameter_name
15
+ end
16
+
17
+ # Calculates hash from passed parameters and key
18
+ def build_hash(key, parameters)
19
+ parameters_string = build_parameters_string key, parameters
20
+ Digest::SHA512.hexdigest parameters_string
21
+ end
22
+
23
+ private
24
+ def build_parameters_string(key, parameters)
25
+ parameters_string = ''
26
+
27
+ @parameters_order.each_with_index do |parameter_name, index|
28
+ if parameter_name == @key_parameter_name
29
+ parameter_value = key.to_s
30
+ else
31
+ parameter_value = parameters[parameter_name].to_s
32
+ end
33
+
34
+ parameters_string += parameter_value.to_s
35
+ parameters_string += ';' unless index == @parameters_order.size - 1
36
+ end
37
+
38
+ parameters_string
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+
3
+ require 'openssl'
4
+ require 'net/http'
5
+
6
+ require 'barzahlen/api/online/hash_builder'
7
+ require 'barzahlen/api/online/response_parser'
8
+
9
+ module Barzahlen
10
+ module Api
11
+ module Online
12
+
13
+ # A wrapper class for Net::HTTP
14
+ # If you want to use your own http client, you must implement the request method and let it
15
+ # return an HTTPResponse compatible object
16
+ class Http
17
+ # sends a request with specified parameters to url, and returns an HTTPResponse object
18
+ def request(url, parameters)
19
+ http_client = Net::HTTP.new url.host, 443
20
+ http_client.use_ssl = true
21
+ http_client.verify_mode = OpenSSL::SSL::VERIFY_PEER
22
+
23
+ request = Net::HTTP::Post.new url.to_s
24
+ request.set_form_data parameters
25
+
26
+ http_client.request request
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,50 @@
1
+ # coding: utf-8
2
+
3
+ module Barzahlen
4
+ module Api
5
+ module Online
6
+
7
+ # Checks requests from Barzahlen-API
8
+ class NotificationHandler
9
+ TRANSACTION_PAID = 'paid'
10
+ TRANSACTION_EXPIRED = 'expired'
11
+ REFUND_COMPLETED = 'refund_completed'
12
+ REFUND_EXPIRED = 'refund_expired'
13
+
14
+ def initialize(api)
15
+ @api = api
16
+ end
17
+
18
+ # validates request and return the parameters
19
+ def validate_request(request_parameters)
20
+ parameters_order = case request_parameters[:state]
21
+ when TRANSACTION_PAID then [:state, :transaction_id, :shop_id, :customer_email,
22
+ :amount, :currency, :order_id, :custom_var_0,
23
+ :custom_var_1, :custom_var_2, :notification_key]
24
+ when TRANSACTION_EXPIRED then [:state, :transaction_id, :shop_id, :customer_email,
25
+ :amount, :currency, :order_id, :custom_var_0,
26
+ :custom_var_1, :custom_var_2, :notification_key]
27
+ when REFUND_COMPLETED then [:state, :refund_transaction_id, :origin_transaction_id,
28
+ :shop_id, :customer_email, :amount, :currency,
29
+ :origin_order_id, :custom_var_0, :custom_var_1,
30
+ :custom_var_2, :notification_key]
31
+ when REFUND_EXPIRED then [:state, :refund_transaction_id, :origin_transaction_id,
32
+ :shop_id, :customer_email, :amount, :currency,
33
+ :origin_order_id, :custom_var_0, :custom_var_1,
34
+ :custom_var_2, :notification_key]
35
+ else raise RuntimeError, "Unknown state '#{request_parameters[:state]}'"
36
+ end
37
+
38
+ expected_hash = @api.build_hash(:notification_key, parameters_order, request_parameters)
39
+ if request_parameters[:hash] != expected_hash
40
+ raise RuntimeError, 'Expected hash does not equal passed hash.' +
41
+ 'Passed: ' + request_parameters[:hash] + ', ' +
42
+ 'Expected: ' + expected_hash
43
+ end
44
+
45
+ request_parameters
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+
3
+ require 'rexml/document'
4
+
5
+ module Barzahlen
6
+ module Api
7
+ module Online
8
+
9
+ # Parses Barzahlen-API response
10
+ class ResponseParser
11
+
12
+ # Parses xml and returns hash
13
+ def self.parse(response_body)
14
+ response_parsed = {}
15
+
16
+ doc = REXML::Document.new response_body
17
+ doc.elements.each('/response/*') do |element|
18
+ response_parsed[element.name.gsub(/\-/, '_').to_sym] = element.text
19
+ end
20
+
21
+ response_parsed
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,57 @@
1
+ # coding: utf-8
2
+
3
+ module Barzahlen
4
+ module Api
5
+ module Online
6
+
7
+ # Manipulates transactions via Barzahlen-API
8
+ class Transaction
9
+ def initialize(api)
10
+ @api = api
11
+ end
12
+
13
+ # create a transaction
14
+ # necessary fields of the transaction are:
15
+ # :customer_email, :amount, :currency, :language, :order_id,
16
+ # :customer_street_nr, :customer_zipcode, :customer_city, :customer_country
17
+ # optional are:
18
+ # :custom_var_0, :custom_var_1, :custom_var_2
19
+ def create(transaction)
20
+ parameters_order = [:shop_id, :customer_email, :amount, :currency, :language, :order_id, :customer_street_nr,
21
+ :customer_zipcode, :customer_city, :customer_country, :custom_var_0, :custom_var_1,
22
+ :custom_var_2, :payment_key]
23
+ @api.request('v1/transactions/create', :payment_key, parameters_order, transaction)
24
+ end
25
+
26
+ # update order-id of a transaction
27
+ def update_order_id(transaction_id, order_id)
28
+ parameters_order = [:shop_id, :transaction_id, :order_id, :payment_key]
29
+ @api.request('v1/transactions/update', :payment_key, parameters_order,
30
+ {:transaction_id => transaction_id, :order_id => order_id})
31
+ end
32
+
33
+ # resend email for a transaction
34
+ def resend_email(transaction_id, language)
35
+ parameters_order = [:shop_id, :transaction_id, :language, :payment_key]
36
+ @api.request('v1/transactions/resend_email', :payment_key, parameters_order,
37
+ {:transaction_id => transaction_id, :language => language})
38
+ end
39
+
40
+ # cancels a transaction
41
+ def cancel(transaction_id, language)
42
+ parameters_order = [:shop_id, :transaction_id, :language, :payment_key]
43
+ @api.request('v1/transactions/cancel', :payment_key, parameters_order,
44
+ {:transaction_id => transaction_id, :language => language})
45
+ end
46
+
47
+ # create a refund for a transaction
48
+ def refund(transaction_id, amount, currency, language)
49
+ parameters_order = [:shop_id, :transaction_id, :amount, :currency, :language, :payment_key]
50
+ @api.request('v1/transactions/refund', :payment_key, parameters_order,
51
+ {:transaction_id => transaction_id, :amount => amount,
52
+ :currency => currency, :language => language})
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,9 @@
1
+ # coding: utf-8
2
+
3
+ module Barzahlen
4
+ module Api
5
+ module Online
6
+ VERSION = '1.0.0'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,58 @@
1
+ # coding: utf-8
2
+
3
+ require 'net/http'
4
+ require 'barzahlen/api/online/http'
5
+ require 'barzahlen/api/online/api'
6
+
7
+ module Barzahlen
8
+ module Api
9
+ module Online
10
+
11
+ # Is responsible for initializing objects to access the Barzahlen-API and check
12
+ # notifications. For using it, you must set a config, in seldom cases an api object.
13
+ #
14
+ # For using the sandbox mode, you must pass the host api.barzahlen.de in the config.
15
+ #
16
+ # = Examples
17
+ # Barzahlen::Api::Online.config = {
18
+ # :shop_id => 'your shop id',
19
+ # :payment_key => 'your payment key',
20
+ # :notification_key => 'your notification key',
21
+ # }
22
+ # api_transaction = Barzahlen::Api::Online.new_transaction_api
23
+ class << self
24
+ HOST = 'api.barzahlen.de'
25
+
26
+ attr_writer :config
27
+ attr_writer :api
28
+
29
+ # Returns an object that represents the Barzahlen-API and all it's methods.
30
+ def new_transaction_api
31
+ autoload :Transaction, 'barzahlen/api/online/transaction'
32
+
33
+ initialize_api
34
+ Barzahlen::Api::Online::Transaction.new @api
35
+ end
36
+
37
+ # Returns an object that validates notification requests, which came from Barzahlen
38
+ def new_notification_handler
39
+ autoload :NotificationHandler, 'barzahlen/api/online/notification_handler'
40
+
41
+ initialize_api
42
+ Barzahlen::Api::Online::NotificationHandler.new @api
43
+ end
44
+
45
+ private
46
+ def initialize_api
47
+ raise ArgumentError, 'You must set a config or api' if @config == nil && @api == nil
48
+ @config[:host] = HOST unless @config.include? :host
49
+
50
+ if @api == nil && @config != nil
51
+ http = Barzahlen::Api::Online::Http.new
52
+ @api = Barzahlen::Api::Online::Api.new http, @config
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,3 @@
1
+ module RubySdk
2
+ VERSION = "0.0.1"
3
+ end
data/lib/ruby_sdk.rb ADDED
@@ -0,0 +1,5 @@
1
+ require "ruby_sdk/version"
2
+
3
+ module RubySdk
4
+ # Your code goes here...
5
+ end