klarna 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +9 -0
- data/.travis.yml +13 -0
- data/Gemfile +14 -0
- data/Guardfile +16 -0
- data/MIT-LICENSE +20 -0
- data/README.textile +139 -0
- data/Rakefile +22 -0
- data/TODO +30 -0
- data/examples/Gemfile +8 -0
- data/examples/config/initializer.rb +15 -0
- data/examples/console.rb +71 -0
- data/examples/public/images/klarna.png +0 -0
- data/examples/public/images/ruby.png +0 -0
- data/examples/views/_address.haml +22 -0
- data/examples/views/_articles.haml +21 -0
- data/examples/views/checkout_page_example.haml +2 -0
- data/examples/views/essential/add_transaction/_form.haml +32 -0
- data/examples/views/essential/add_transaction/result.haml +7 -0
- data/examples/views/essential/calculate_monthly_cost/_form.haml +16 -0
- data/examples/views/essential/calculate_monthly_cost/result.haml +7 -0
- data/examples/views/essential/get_addresses/_form.haml +9 -0
- data/examples/views/essential/get_addresses/result.haml +8 -0
- data/examples/views/index.haml +296 -0
- data/examples/views/layout.haml +48 -0
- data/examples/views/payment_terms_example.haml +102 -0
- data/examples/views/product_page_example.haml +2 -0
- data/examples/views/reservation/activate_reservation/_form.haml +54 -0
- data/examples/views/reservation/activate_reservation/result.haml +7 -0
- data/examples/views/reservation/cancel_reservation/_form.haml +8 -0
- data/examples/views/reservation/cancel_reservation/result.haml +7 -0
- data/examples/views/reservation/change_reservation/_form.haml +10 -0
- data/examples/views/reservation/change_reservation/result.haml +7 -0
- data/examples/views/reservation/reserve_amount/_form.haml +58 -0
- data/examples/views/reservation/reserve_amount/result.haml +7 -0
- data/examples/views/reservation/reserve_ocr_numbers/_form.haml +8 -0
- data/examples/views/reservation/reserve_ocr_numbers/result.haml +7 -0
- data/examples/views/reservation/split_reservation/_form.haml +14 -0
- data/examples/views/reservation/split_reservation/result.haml +7 -0
- data/examples/views/special/get_pclasses/_form.haml +8 -0
- data/examples/views/special/get_pclasses/result.haml +7 -0
- data/examples/views/special/invoice_address/_form.haml +8 -0
- data/examples/views/special/invoice_address/result.haml +7 -0
- data/examples/views/special/invoice_amount/_form.haml +8 -0
- data/examples/views/special/invoice_amount/result.haml +7 -0
- data/examples/views/special/is_invoice_paid/_form.haml +8 -0
- data/examples/views/special/is_invoice_paid/result.haml +7 -0
- data/examples/views/special/update_charge_amount/_form.haml +15 -0
- data/examples/views/special/update_charge_amount/result.haml +7 -0
- data/examples/views/special/update_goods_quantity/_form.haml +17 -0
- data/examples/views/special/update_goods_quantity/result.haml +7 -0
- data/examples/views/special/update_order_number/_form.haml +10 -0
- data/examples/views/special/update_order_number/result.haml +7 -0
- data/examples/views/useful/activate_invoice/_form.haml +9 -0
- data/examples/views/useful/activate_invoice/result.haml +7 -0
- data/examples/views/useful/credit_invoice/_form.haml +11 -0
- data/examples/views/useful/credit_invoice/result.haml +7 -0
- data/examples/views/useful/delete_invoice/_form.haml +9 -0
- data/examples/views/useful/delete_invoice/result.haml +7 -0
- data/examples/views/useful/email_invoice/_form.haml +9 -0
- data/examples/views/useful/email_invoice/result.haml +7 -0
- data/examples/views/useful/has_account/_form.haml +9 -0
- data/examples/views/useful/has_account/result.haml +7 -0
- data/examples/views/useful/return_amount/_form.haml +15 -0
- data/examples/views/useful/return_amount/result.haml +7 -0
- data/examples/views/useful/send_invoice/_form.haml +9 -0
- data/examples/views/useful/send_invoice/result.haml +7 -0
- data/examples/web.rb +349 -0
- data/klarna.gemspec +34 -0
- data/lib/klarna.rb +175 -0
- data/lib/klarna/api.rb +170 -0
- data/lib/klarna/api/client.rb +128 -0
- data/lib/klarna/api/constants.rb +638 -0
- data/lib/klarna/api/errors.rb +154 -0
- data/lib/klarna/api/methods.rb +16 -0
- data/lib/klarna/api/methods/cost_calculations.rb +134 -0
- data/lib/klarna/api/methods/invoicing.rb +304 -0
- data/lib/klarna/api/methods/reservation.rb +149 -0
- data/lib/klarna/api/methods/standard.rb +123 -0
- data/lib/klarna/version.rb +5 -0
- data/test/fixtures/api/companies.yml +97 -0
- data/test/fixtures/api/pclasses.yml +37 -0
- data/test/fixtures/api/persons.yml +144 -0
- data/test/fixtures/api/stores.yml +6 -0
- data/test/fixtures/klarna.yml +10 -0
- data/test/klarna/api/client_test.rb +272 -0
- data/test/klarna/api/errors_test.rb +46 -0
- data/test/klarna/api/methods/cost_calculations_test.rb +78 -0
- data/test/klarna/api/methods/invoicing_test.rb +409 -0
- data/test/klarna/api/methods/reservation_test.rb +66 -0
- data/test/klarna/api/methods/standard_test.rb +244 -0
- data/test/klarna/api_test.rb +137 -0
- data/test/klarna_test.rb +204 -0
- data/test/support/assertions_helper.rb +40 -0
- data/test/test_helper.rb +55 -0
- metadata +312 -0
data/lib/klarna.rb
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# require 'rubygems'
|
3
|
+
# require 'bundler'
|
4
|
+
# Bundler.require
|
5
|
+
require 'i18n'
|
6
|
+
require 'active_support/all'
|
7
|
+
|
8
|
+
module Klarna
|
9
|
+
|
10
|
+
autoload :API, 'klarna/api'
|
11
|
+
autoload :VERSION, 'klarna/version'
|
12
|
+
|
13
|
+
module API
|
14
|
+
autoload :Client, 'klarna/api/client'
|
15
|
+
autoload :Constants, 'klarna/api/constants'
|
16
|
+
autoload :Errors, 'klarna/api/errors'
|
17
|
+
|
18
|
+
module Methods
|
19
|
+
autoload :Standard, 'klarna/api/methods/standard'
|
20
|
+
autoload :Invoicing, 'klarna/api/methods/invoicing'
|
21
|
+
autoload :Reservation, 'klarna/api/methods/reservation'
|
22
|
+
autoload :CostCalculations, 'klarna/api/methods/cost_calculations'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class KlarnaConfigError < ::StandardError
|
27
|
+
end
|
28
|
+
|
29
|
+
DEFAULT_STORE_CONFIG_FILE = File.join(ENV['HOME'], '.klarna.yml') unless defined?(::Klarna::DEFAULT_STORE_CONFIG_FILE)
|
30
|
+
VALID_COUNTRIES = [:SE, :NO, :FI, :DK] unless defined?(::Klarna::VALID_COUNTRIES)
|
31
|
+
DEFAULT_COUNTRY = VALID_COUNTRIES.first unless defined?(::Klarna::DEFAULT_COUNTRY)
|
32
|
+
DEFAULT_MODE = :test unless defined?(::Klarna::DEFAULT_MODE)
|
33
|
+
|
34
|
+
# Specifies running mode: +:test+ (alla actions gets virtual) or +:production+ (live)
|
35
|
+
# Default: +:test+
|
36
|
+
mattr_accessor :mode
|
37
|
+
@@mode = :test
|
38
|
+
|
39
|
+
# Country used to ensure that params sent to Klarna service is correct.
|
40
|
+
# Default: +:SE+
|
41
|
+
mattr_accessor :country
|
42
|
+
@@country = ::Klarna::DEFAULT_COUNTRY
|
43
|
+
|
44
|
+
# Klarna e-store ID (a.k.a. "eid") used for Klarna API authentication.
|
45
|
+
# Default: +nil+
|
46
|
+
# NOTE: If +nil+, Klarna will look for credentials in file specified by +Devise.store_config_file+.
|
47
|
+
mattr_accessor :store_id
|
48
|
+
@@store_id = nil
|
49
|
+
|
50
|
+
# Klarna e-store shared secret token used for Klarna API authentication.
|
51
|
+
# Default: +nil+
|
52
|
+
# NOTE: If +nil+, Klarna will look for credentials in file specified by +Devise.credentials_file+.
|
53
|
+
mattr_accessor :store_secret
|
54
|
+
@@store_secret = nil
|
55
|
+
|
56
|
+
# Klarna e-store-specific pclasses (a.k.a. campaigns).
|
57
|
+
# Default: +nil+
|
58
|
+
#
|
59
|
+
# NOTE:
|
60
|
+
# * Required for campaigns
|
61
|
+
# * This should maybe be initialized from database to make more dynamic (e.g. admin inteface).
|
62
|
+
#
|
63
|
+
mattr_accessor :store_pclasses
|
64
|
+
@@store_pclasses = nil
|
65
|
+
|
66
|
+
# Path to a YAML file containing API credentials - used only if +store_id+ and +store_secret+ are not set.
|
67
|
+
# Default: +"~/.klarna.yml"+
|
68
|
+
mattr_accessor :store_config_file
|
69
|
+
@@store_config_file = ::Klarna::DEFAULT_STORE_CONFIG_FILE
|
70
|
+
|
71
|
+
# The logger to use in log mode.
|
72
|
+
# Default: +::Logger.new(::STDOUT)+
|
73
|
+
mattr_accessor :logger
|
74
|
+
@@logger = ::Logger.new(::STDOUT)
|
75
|
+
|
76
|
+
# Sets if activity should be logged or not - for high-level debugging.
|
77
|
+
# Default: +false+
|
78
|
+
mattr_accessor :logging
|
79
|
+
@@logging = false
|
80
|
+
|
81
|
+
# Sets if Net::HTTP activity should be logged or not - for low-level debugging.
|
82
|
+
# Default: +false+
|
83
|
+
mattr_accessor :http_logging
|
84
|
+
@@http_logging = false
|
85
|
+
|
86
|
+
class << self
|
87
|
+
|
88
|
+
# Configuration DSL helper method.
|
89
|
+
#
|
90
|
+
# == Usage/Example:
|
91
|
+
#
|
92
|
+
# Klarna::Setup do |config|
|
93
|
+
# config.country = :SE
|
94
|
+
# # etc.
|
95
|
+
# end
|
96
|
+
#
|
97
|
+
def setup
|
98
|
+
yield self
|
99
|
+
self.load_credentials_from_file unless self.store_id || self.store_secret
|
100
|
+
end
|
101
|
+
alias :configure :setup
|
102
|
+
|
103
|
+
# Reset to defaults - mostly usable in specs.
|
104
|
+
#
|
105
|
+
def reset!
|
106
|
+
self.mode = ::Klarna::DEFAULT_MODE
|
107
|
+
self.country = ::Klarna::DEFAULT_COUNTRY
|
108
|
+
self.store_id = nil
|
109
|
+
self.store_secret = nil
|
110
|
+
self.store_pclasses = nil
|
111
|
+
self.store_config_file = ::Klarna::DEFAULT_STORE_CONFIG_FILE
|
112
|
+
self.logger = ::Logger.new(::STDOUT)
|
113
|
+
self.logging = false
|
114
|
+
self.http_logging = false
|
115
|
+
end
|
116
|
+
|
117
|
+
# Logging helper for debugging purposes.
|
118
|
+
#
|
119
|
+
def log(message, level = :info)
|
120
|
+
return unless self.logging?
|
121
|
+
level = :info if level.blank?
|
122
|
+
self.logger ||= ::Logger.new(::STDOUT)
|
123
|
+
self.logger.send(level.to_sym, "[klarna:] #{level.to_s.upcase} #{message}")
|
124
|
+
end
|
125
|
+
|
126
|
+
# Logging helper for debugging "log return value"-cases.
|
127
|
+
#
|
128
|
+
def log_result(label, &block)
|
129
|
+
result = block.call
|
130
|
+
self.log label % result.inspect
|
131
|
+
result
|
132
|
+
end
|
133
|
+
|
134
|
+
# Optional: Try to load credentials from a system file.
|
135
|
+
#
|
136
|
+
def load_credentials_from_file(force = false)
|
137
|
+
begin
|
138
|
+
store_config = File.open(self.store_config_file) { |file| YAML.load(file).with_indifferent_access }
|
139
|
+
self.store_id = store_config[self.mode][:store_id] if force || self.store_id.nil?
|
140
|
+
self.store_secret = store_config[self.mode][:store_secret] if force || self.store_secret.nil?
|
141
|
+
self.store_pclasses = store_config[self.mode][:store_pclasses] if force || self.store_pclasses.nil?
|
142
|
+
rescue
|
143
|
+
raise KlarnaConfigError, "Could not load store details from: #{self.store_config_file.inspect}"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def store_id=(value)
|
148
|
+
@@store_id = value ? value.to_i : value
|
149
|
+
end
|
150
|
+
|
151
|
+
def store_secret=(value)
|
152
|
+
@@store_secret = value ? value.to_s.strip : value
|
153
|
+
end
|
154
|
+
|
155
|
+
def country=(value)
|
156
|
+
@@country = value.to_s.upcase.to_sym rescue ::Klarna::DEFAULT_COUNTRY
|
157
|
+
end
|
158
|
+
|
159
|
+
def mode=(value)
|
160
|
+
@@mode = value.to_s.downcase.to_sym rescue ::Klarna::DEFAULT_MODE
|
161
|
+
end
|
162
|
+
|
163
|
+
def valid_countries
|
164
|
+
::Klarna::VALID_COUNTRIES
|
165
|
+
end
|
166
|
+
|
167
|
+
def default_country
|
168
|
+
::Klarna::DEFAULT_COUNTRY
|
169
|
+
end
|
170
|
+
|
171
|
+
alias :logging? :logging
|
172
|
+
alias :http_logging? :http_logging
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
data/lib/klarna/api.rb
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'iconv'
|
3
|
+
require 'digest/md5'
|
4
|
+
require 'digest/sha2'
|
5
|
+
require 'xmlrpc/base64'
|
6
|
+
|
7
|
+
require 'klarna/api/constants'
|
8
|
+
require 'klarna/api/errors'
|
9
|
+
|
10
|
+
module Klarna
|
11
|
+
module API
|
12
|
+
|
13
|
+
# == Reference:
|
14
|
+
#
|
15
|
+
# * http://integration.klarna.com/api-functions
|
16
|
+
#
|
17
|
+
# == Note:
|
18
|
+
#
|
19
|
+
# All input data strings should be coded in accordance with ISO-8859-1.
|
20
|
+
#
|
21
|
+
# This implementation is not 1-to-1 implementation of the Klarna API functions.
|
22
|
+
# The methods are refactored/cleaned up to meet Ruby code standards; avoid
|
23
|
+
# unessecary code-repetition and spaghetti-code like the other implementations.
|
24
|
+
# Same functionality can be achieved though; see the RDocs.
|
25
|
+
#
|
26
|
+
# To obtain pclasses - or download the pclasses file:
|
27
|
+
#
|
28
|
+
# 1. Log in to Kreditor Online.
|
29
|
+
# 2. Click on "Display store"
|
30
|
+
# 3. Click on "Click here to view campaigns".
|
31
|
+
#
|
32
|
+
# ...or use the API-method +::Klarna::API.get_pclasses+.
|
33
|
+
#
|
34
|
+
|
35
|
+
include ::Klarna::API::Constants
|
36
|
+
include ::Klarna::API::Errors
|
37
|
+
|
38
|
+
@@client = nil
|
39
|
+
|
40
|
+
class << self
|
41
|
+
|
42
|
+
# Re-use or (re-)initialize a new Klarna XML-RPC API client.
|
43
|
+
#
|
44
|
+
def client(force_new = false)
|
45
|
+
begin
|
46
|
+
if force_new || @@client.nil?
|
47
|
+
@@client = ::Klarna::API::Client.new
|
48
|
+
end
|
49
|
+
rescue => e
|
50
|
+
::Klarna.log e, :error
|
51
|
+
end
|
52
|
+
@@client
|
53
|
+
end
|
54
|
+
|
55
|
+
def key_for(kind, value)
|
56
|
+
begin
|
57
|
+
kind = validated_kind(kind)
|
58
|
+
rescue => e
|
59
|
+
raise e
|
60
|
+
end
|
61
|
+
|
62
|
+
begin
|
63
|
+
is_correct_format = !(value.to_s =~ /^\d+$/)
|
64
|
+
constants = ::Klarna::API.const_get(kind)
|
65
|
+
key = is_correct_format ? value : constants.invert[value.to_i] # BUG: Should lookup the value's key.
|
66
|
+
rescue
|
67
|
+
raise ::Klarna::API::KlarnaArgumentError, "Invalid '#{kind}': #{value.inspect}"
|
68
|
+
end
|
69
|
+
|
70
|
+
key ? key.to_sym : nil
|
71
|
+
end
|
72
|
+
|
73
|
+
def id_for(kind, value)
|
74
|
+
begin
|
75
|
+
kind = validated_kind(kind)
|
76
|
+
rescue => e
|
77
|
+
raise e
|
78
|
+
end
|
79
|
+
|
80
|
+
begin
|
81
|
+
is_correct_format = (value.to_s =~ /^\d+$/)
|
82
|
+
constants = ::Klarna::API.const_get(kind)
|
83
|
+
id = is_correct_format ? value.to_i : constants[value.to_s.upcase.to_sym]
|
84
|
+
rescue
|
85
|
+
raise ::Klarna::API::KlarnaArgumentError, "Invalid '#{kind}': #{value.inspect}"
|
86
|
+
end
|
87
|
+
|
88
|
+
id ? id.to_i : nil
|
89
|
+
end
|
90
|
+
|
91
|
+
# Validate if specified +kind+ is a valid constant.
|
92
|
+
#
|
93
|
+
def validated_kind(kind)
|
94
|
+
valid_kinds = [:country, :currency, :language, :pno_format, :address_format, :shipment_type, :pclass, :mobile, :invoice, :goods, :monthly_cost]
|
95
|
+
valid_kinds.collect! do |valid_kind|
|
96
|
+
[valid_kind.to_s.singularize.to_sym, valid_kind.to_s.pluralize.to_sym]
|
97
|
+
end
|
98
|
+
valid_kinds.flatten!
|
99
|
+
kind = kind.to_s.pluralize.to_sym
|
100
|
+
|
101
|
+
unless kind.is_a?(String) || kind.is_a?(Symbol)
|
102
|
+
raise ::Klarna::API::KlarnaArgumentError, "Not a valid kind: #{kind.inspect}. Expects a symbol or a string: #{valid_kinds.join(', ')}"
|
103
|
+
end
|
104
|
+
|
105
|
+
unless valid_kinds.include?(kind.to_s.downcase.to_sym)
|
106
|
+
raise ::Klarna::API::KlarnaArgumentError, "Not a valid kind: #{kind.inspect}. Valid kinds: #{valid_kinds.join(', ')}"
|
107
|
+
end
|
108
|
+
|
109
|
+
kind.to_s.upcase.to_sym
|
110
|
+
end
|
111
|
+
|
112
|
+
# Parse, validate, and cast a method argument before RPC-call.
|
113
|
+
#
|
114
|
+
def validate_arg(value, cast_to, format_expression, strip_expression = nil, &block)
|
115
|
+
raise ::Klarna::API::KlarnaArgumentError,
|
116
|
+
"Argument cast_to should be Symbol, but was #{cast_to.class.name}." unless cast_to.is_a?(Symbol)
|
117
|
+
raise ::Klarna::API::KlarnaArgumentError,
|
118
|
+
"Argument regexp should be Regexp, but was #{format_expression.class.name}." unless format_expression.is_a?(Regexp)
|
119
|
+
raise ::Klarna::API::KlarnaArgumentError,
|
120
|
+
"Argument strip should be Regexp, but was #{strip_expression.class.name}." unless strip_expression.is_a?(Regexp)
|
121
|
+
|
122
|
+
value = value.to_s.gsub(strip_expression, '') if strip_expression
|
123
|
+
|
124
|
+
unless value.to_s =~ format_expression
|
125
|
+
raise ::Klarna::API::KlarnaArgumentError, "Invalid argument: #{value.inspect}. Expected format: #{format_expression.inspect}"
|
126
|
+
end
|
127
|
+
|
128
|
+
# Pass value to block - for type casting, etc. - if given.
|
129
|
+
value = block.call(value) if block_given?
|
130
|
+
|
131
|
+
value.tap do |v|
|
132
|
+
case cast_to
|
133
|
+
when :string then v.to_s
|
134
|
+
when :integer then v.to_i
|
135
|
+
when :decimal then v.to_f # number of decimals?
|
136
|
+
when :date then v # TODO
|
137
|
+
else
|
138
|
+
raise ::Klarna::API::KlarnaArgumentError, "Invalid cast_to value: #{cast_to.inspect}. "
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def parse_flags(constant_name, flags)
|
144
|
+
if flags.is_a?(Hash)
|
145
|
+
flags = flags.sum { |k,v|
|
146
|
+
::Klarna::API.const_get(constant_name.to_s.upcase.to_sym)[k.to_s.upcase.to_sym]
|
147
|
+
}
|
148
|
+
end
|
149
|
+
flags.to_i
|
150
|
+
end
|
151
|
+
|
152
|
+
def digest(*args)
|
153
|
+
string = args.join(':')
|
154
|
+
iso_value = self.encode(string)
|
155
|
+
|
156
|
+
|
157
|
+
hex_md5_digest = [*::Digest::MD5.hexdigest(iso_value)].pack('H*')
|
158
|
+
base64_digest = ::XMLRPC::Base64.encode(hex_md5_digest).strip
|
159
|
+
hex_sha512_digest = [*Digest::SHA512.hexdigest(iso_value)].pack('H*')
|
160
|
+
base64_digest = ::XMLRPC::Base64.encode(hex_sha512_digest).strip
|
161
|
+
end
|
162
|
+
|
163
|
+
def encode(string, from_encoding = 'utf-8')
|
164
|
+
::Iconv.conv(::Klarna::API::PROTOCOL_ENCODING, from_encoding, string)
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'xmlrpc/client'
|
3
|
+
|
4
|
+
require 'klarna/api/methods'
|
5
|
+
|
6
|
+
module Klarna
|
7
|
+
module API
|
8
|
+
class Client < ::XMLRPC::Client
|
9
|
+
|
10
|
+
include ::Klarna::API::Methods
|
11
|
+
|
12
|
+
attr_accessor :store_id,
|
13
|
+
:store_secret,
|
14
|
+
:mode,
|
15
|
+
:timeout,
|
16
|
+
:last_request_headers,
|
17
|
+
:last_request_params,
|
18
|
+
:last_response,
|
19
|
+
:client_ip,
|
20
|
+
:protocol,
|
21
|
+
:host,
|
22
|
+
:port
|
23
|
+
|
24
|
+
def initialize(*args)
|
25
|
+
self.store_id = args.shift || ::Klarna.store_id
|
26
|
+
self.store_secret = args.shift || ::Klarna.store_secret
|
27
|
+
|
28
|
+
if self.store_id.blank? || self.store_secret.blank?
|
29
|
+
raise ::Klarna::API::KlarnaCredentialsError, "Both STORE_ID or STORE_SECRET must be set."
|
30
|
+
end
|
31
|
+
|
32
|
+
options = args.extract_options!
|
33
|
+
self.client_ip = options[:client_ip].presence || '127.0.0.1'
|
34
|
+
self.mode = options.key?(:mode) ? options[:mode] : ::Klarna.mode
|
35
|
+
self.timeout = options.key?(:timeout) ? options[:timeout] : 10 # seconds
|
36
|
+
|
37
|
+
unless ::Klarna::API::END_POINT.keys.include?(self.mode)
|
38
|
+
raise "No such mode: #{self.mode.inspect}. " <<
|
39
|
+
"Valid modes: #{::Klarna::API::END_POINT.keys.collect(&:inspect).join(', ')}"
|
40
|
+
end
|
41
|
+
|
42
|
+
begin
|
43
|
+
::Klarna.log "Endpoint URI: %s" % self.endpoint_uri.inspect
|
44
|
+
|
45
|
+
super(self.host, '/', self.port, nil, nil, nil, nil, self.use_ssl?, self.timeout)
|
46
|
+
|
47
|
+
self.http_header_extra ||= {}
|
48
|
+
self.http_header_extra.merge!(self.content_type_headers)
|
49
|
+
|
50
|
+
self.instance_variable_get(:@http).set_debug_output(::Klarna.logger) if ::Klarna.http_logging?
|
51
|
+
rescue ::XMLRPC::FaultException => e
|
52
|
+
raise ::Klarna::API::KlarnaServiceError.new(e.faultCode, e.faultString)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def call(service_method, *args)
|
57
|
+
args.collect! { |arg| arg.is_a?(String) ? ::Iconv.conv('utf-8', ::Klarna::API::PROTOCOL_ENCODING, arg) : arg }
|
58
|
+
::Klarna.log "Method: #{service_method}"
|
59
|
+
::Klarna.log "Params: %s" % self.add_meta_params(*args).inspect
|
60
|
+
|
61
|
+
self.last_request_headers = http_header_extra
|
62
|
+
|
63
|
+
begin
|
64
|
+
::Klarna.log_result("Result: %s") do
|
65
|
+
params = self.add_meta_params(*args)
|
66
|
+
self.last_request_params = params
|
67
|
+
self.last_response = super(service_method, *params)
|
68
|
+
end
|
69
|
+
rescue ::XMLRPC::FaultException => e
|
70
|
+
raise ::Klarna::API::KlarnaServiceError.new(e.faultCode, e.faultString)
|
71
|
+
rescue ::Timeout::Error => e
|
72
|
+
raise ::Klarna::API::KlarnaServiceError.new(-1, e.message)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def ssl?
|
77
|
+
self.protocol == 'https'
|
78
|
+
end
|
79
|
+
alias :use_ssl? :ssl?
|
80
|
+
|
81
|
+
def protocol
|
82
|
+
@protocol = ::Klarna::API::END_POINT[self.mode][:protocol]
|
83
|
+
end
|
84
|
+
|
85
|
+
def host
|
86
|
+
@host = ::Klarna::API::END_POINT[self.mode][:host]
|
87
|
+
end
|
88
|
+
|
89
|
+
def port
|
90
|
+
@port = ::Klarna::API::END_POINT[self.mode][:port]
|
91
|
+
end
|
92
|
+
|
93
|
+
def endpoint_uri
|
94
|
+
@endpoint_uri = "#{self.protocol}://#{self.host}:#{self.port}"
|
95
|
+
end
|
96
|
+
|
97
|
+
protected
|
98
|
+
|
99
|
+
# Request content-type headers.
|
100
|
+
#
|
101
|
+
def content_type_headers
|
102
|
+
{
|
103
|
+
:'Accept-Encoding' => 'deflate,gzclient_ip',
|
104
|
+
:'Content-Type' => "text/xml;charset=#{::Klarna::API::PROTOCOL_ENCODING}",
|
105
|
+
:'Accept-Charset' => 'iso-8859-1', # REVISIT: 'UTF-8,ISO-8859-1,US-ASCII',
|
106
|
+
:'Connection' => 'close',
|
107
|
+
:'User-Agent' => 'ruby/xmlrpc' # Note: Default "User-Agent" gives 400-error.
|
108
|
+
}.with_indifferent_access
|
109
|
+
end
|
110
|
+
|
111
|
+
# Ensure that the required client info params get sent with each Klarna API request.
|
112
|
+
# Without these the Klarna API will get a service error response.
|
113
|
+
#
|
114
|
+
def add_meta_params(*args)
|
115
|
+
args.unshift *[::Klarna::API::PROTOCOL_VERSION, ::XMLRPC::Client::USER_AGENT]
|
116
|
+
args
|
117
|
+
end
|
118
|
+
|
119
|
+
# Pass additional required digest args to the raw digest method.
|
120
|
+
#
|
121
|
+
def digest(*args)
|
122
|
+
options = args.extract_options!
|
123
|
+
::Klarna::API.digest(*[(self.store_id unless options[:store_id] == false), args, self.store_secret].compact.flatten)
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|