klarna-checkout 0.0.1

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: 7e38e512946fd7304c91accccae965f8742e3c99
4
+ data.tar.gz: 575e40eeb308bede813d8837e379968de3fd478d
5
+ SHA512:
6
+ metadata.gz: 76593c8f81683dbdf32e7a76517ca3dcfc0e8b41abb8cbe2e77831d27d5c2c682e7579d27388b2f0c815cff9519a71097c578ec227408bf405471d9d24d5e91d
7
+ data.tar.gz: d791fc372219a818af9398670c3f204d161aec6cd129a5504ebbca34659ccccc2bd72f646ce906aa51199d134bf97305bd3e8a50edade37f3f0eabf31b6962e7
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in klarna-checkout.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,5 @@
1
+ guard :rspec, failed_mode: :none do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
4
+ watch('spec/spec_helper.rb') { "spec" }
5
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Theodor Tonum
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,69 @@
1
+ # Klarna Checkout
2
+
3
+ Unofficial Ruby Wrapper for Klarnas Checkout Rest API.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'klarna-checkout'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install klarna-checkout
18
+
19
+ ## Usage
20
+
21
+ ```ruby
22
+ require 'klarna/checkout'
23
+
24
+ client = Klarna::Checkout::Client.new({ shared_secret: 'your-shared-secret' })
25
+
26
+ # Initialize an order
27
+ order = Klarna::Checkout::Order.new({
28
+ purchase_country: 'NO',
29
+ purchase_currency: 'NOK',
30
+ locale: 'nb-no',
31
+ cart: {
32
+ items: [{
33
+ reference: '1123581220325',
34
+ name: 'Widget',
35
+ quantity: 1,
36
+ unit_price: 666,
37
+ tax_rate: 2500
38
+ }]
39
+ },
40
+ merchant: {
41
+ id: '1337',
42
+ terms_uri: 'http://www.example.com/terms',
43
+ checkout_uri: 'http://www.example.com/checkout',
44
+ confirmation_uri: 'http://www.example.com/confirmation_uri',
45
+ push_uri: 'http://www.example.com/push'
46
+ }
47
+ })
48
+
49
+ # Create the order with Klarna
50
+ client.create_order(order)
51
+ order.id # => will output the ID of the order (no other attributes are updated)
52
+
53
+ # Read an order from Klarna
54
+ order = client.read_order("1234ABCD")
55
+ ```
56
+
57
+ ## TODO
58
+
59
+ * Raise exceptions on errors from API
60
+ * Validation of objects according to documentation
61
+ * Respect readonly attributes
62
+
63
+ ## Contributing
64
+
65
+ 1. Fork it
66
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
67
+ 3. Commit your changes, don't forget to add tests (`git commit -am 'Add some feature'`)
68
+ 4. Push to the branch (`git push origin my-new-feature`)
69
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'klarna/checkout/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "klarna-checkout"
8
+ spec.version = Klarna::Checkout::VERSION
9
+ spec.authors = ["Theodor Tonum"]
10
+ spec.email = ["theodor@tonum.no"]
11
+ spec.description = %q{Ruby Wrapper for Klarna Checkout Rest API}
12
+ spec.summary = %q{...}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "faraday"
22
+ spec.add_dependency "activemodel"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.3"
25
+ spec.add_development_dependency "rake"
26
+ spec.add_development_dependency "rspec"
27
+ spec.add_development_dependency "guard"
28
+ spec.add_development_dependency "guard-rspec"
29
+ spec.add_development_dependency "webmock"
30
+ spec.add_development_dependency "vcr"
31
+ spec.add_development_dependency "shoulda-matchers"
32
+ end
@@ -0,0 +1,17 @@
1
+ require "klarna/checkout/version"
2
+ require "klarna/checkout/client"
3
+
4
+ require "klarna/checkout/resource"
5
+
6
+ require "klarna/checkout/address"
7
+ require "klarna/checkout/cart"
8
+ require "klarna/checkout/customer"
9
+ require "klarna/checkout/gui"
10
+ require "klarna/checkout/merchant"
11
+ require "klarna/checkout/order"
12
+
13
+ module Klarna
14
+ module Checkout
15
+ # Your code goes here...
16
+ end
17
+ end
@@ -0,0 +1,22 @@
1
+ module Klarna
2
+ module Checkout
3
+ class Address < Resource
4
+ attr_accessor :given_name, :family_name, :care_of, :street_address,
5
+ :postal_code, :city, :country, :email, :phone
6
+
7
+ def as_json
8
+ {
9
+ :given_name => @given_name,
10
+ :family_name => @family_name,
11
+ :care_of => @care_of,
12
+ :street_address => @street_address,
13
+ :postal_code => @postal_code,
14
+ :city => @city,
15
+ :country => @country,
16
+ :email => @email,
17
+ :phone => @phone
18
+ }
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,21 @@
1
+ require "klarna/checkout/cart_item"
2
+
3
+ module Klarna
4
+ module Checkout
5
+ class Cart < Resource
6
+ attr_accessor :total_price_including_tax, :total_price_excluding_tax,
7
+ :total_tax_amount
8
+
9
+ has_many :items, Klarna::Checkout::CartItem
10
+
11
+ def as_json
12
+ {
13
+ :total_price_including_tax => @total_price_including_tax,
14
+ :total_price_excluding_tax => @total_price_excluding_tax,
15
+ :total_tax_amount => @total_tax_amount,
16
+ :items => @items.map(&:as_json)
17
+ }
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,27 @@
1
+ module Klarna
2
+ module Checkout
3
+ class CartItem < Resource
4
+ attr_accessor :type, :ean, :reference, :name, :uri, :image_uri, :quantity,
5
+ :unit_price, :total_price_excluding_tax, :total_tax_amount,
6
+ :total_price_including_tax, :discount_rate, :tax_rate
7
+
8
+ def as_json
9
+ {
10
+ :type => @type,
11
+ :ean => @ean,
12
+ :reference => @reference,
13
+ :name => @name,
14
+ :uri => @uri,
15
+ :image_uri => @image_uri,
16
+ :quantity => @quantity,
17
+ :unit_price => @unit_price,
18
+ :total_price_excluding_tax => @total_price_excluding_tax,
19
+ :total_tax_amount => @total_tax_amount,
20
+ :total_price_including_tax => @total_price_including_tax,
21
+ :discount_rate => @discount_rate,
22
+ :tax_rate => @tax_rate
23
+ }
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,57 @@
1
+ require 'digest/sha2'
2
+ require 'base64'
3
+ require 'faraday'
4
+
5
+ module Klarna
6
+ module Checkout
7
+ class Client
8
+ attr_accessor :shared_secret
9
+
10
+ def initialize(args = {})
11
+ args.each do |(k,v)|
12
+ self.public_send("#{k}=", v)
13
+ end
14
+ end
15
+
16
+ def create_order(order)
17
+ request_body = order.to_json
18
+ response = https_connection.post do |req|
19
+ req.url '/checkout/orders'
20
+
21
+ req.headers['Authorization'] = "Klarna #{sign_payload(request_body)}"
22
+ req.headers['Accept'] = 'application/vnd.klarna.checkout.aggregated-order-v2+json',
23
+ req.headers['Content-Type'] = 'application/vnd.klarna.checkout.aggregated-order-v2+json'
24
+ req.headers['Accept-Encoding'] = ''
25
+
26
+ req.body = request_body
27
+ end
28
+ order.id = response.headers['Location'].split('/').last
29
+ order
30
+ end
31
+
32
+ def read_order(id)
33
+ response = https_connection.get do |req|
34
+ req.url "/checkout/orders/#{id}"
35
+
36
+ req.headers['Authorization'] = "Klarna #{sign_payload}"
37
+ req.headers['Accept'] = 'application/vnd.klarna.checkout.aggregated-order-v2+json'
38
+ req.headers['Accept-Encoding'] = ''
39
+ end
40
+ Order.new(JSON.parse(response.body))
41
+ end
42
+
43
+ # Based on example from:
44
+ # http://developers.klarna.com/en/api-references-v1/klarna-checkout#authorization
45
+ def sign_payload(request_body = '')
46
+ payload = "#{request_body}#{shared_secret}"
47
+ Digest::SHA256.base64digest(payload)
48
+ end
49
+
50
+ private
51
+
52
+ def https_connection
53
+ @https_connection ||= Faraday.new(url: 'https://checkout.testdrive.klarna.com')
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,19 @@
1
+ module HasMany
2
+ def has_many(association, klass = nil)
3
+ attr_accessor association
4
+
5
+ define_method "#{association}=" do |new_value|
6
+ new_value = Array(new_value)
7
+ inst_var = "@#{association}"
8
+ case new_value.first
9
+ when klass
10
+ instance_variable_set(inst_var, new_value)
11
+ when Hash
12
+ new_value = new_value.map { |hash| klass.new(hash) }
13
+ instance_variable_set(inst_var, new_value)
14
+ else
15
+ raise "Unsupported type for relation #{association}: #{new_value.first.class.to_s}"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,17 @@
1
+ module HasOne
2
+ def has_one(association, klass = nil)
3
+ attr_accessor association
4
+
5
+ define_method "#{association}=" do |new_value|
6
+ inst_var = "@#{association}"
7
+ case new_value
8
+ when klass
9
+ instance_variable_set(inst_var, new_value)
10
+ when Hash
11
+ instance_variable_set(inst_var, klass.new(new_value))
12
+ else
13
+ raise "Unsupported type for relation #{association}: #{new_value.class.to_s}"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ module Klarna
2
+ module Checkout
3
+ class Customer < Resource
4
+ attr_accessor :type
5
+
6
+ def as_json
7
+ {
8
+ :type => @type
9
+ }
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ module Klarna
2
+ module Checkout
3
+ class Gui < Resource
4
+ attr_accessor :layout, :options, :snippet
5
+
6
+ def as_json
7
+ {
8
+ :layout => @layout,
9
+ :options => @options
10
+ }
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,19 @@
1
+ module Klarna
2
+ module Checkout
3
+ class Merchant < Resource
4
+ attr_accessor :id, :terms_uri, :checkout_uri, :confirmation_uri,
5
+ :push_uri, :validation_uri
6
+
7
+ def as_json
8
+ {
9
+ :id => @id,
10
+ :terms_uri => @terms_uri,
11
+ :checkout_uri => @checkout_uri,
12
+ :confirmation_uri => @confirmation_uri,
13
+ :push_uri => @push_uri,
14
+ :validation_uri => @validation_uri
15
+ }
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,33 @@
1
+ require 'json'
2
+
3
+ module Klarna
4
+ module Checkout
5
+ class Order < Resource
6
+ attr_accessor :id, :status, :reference, :reservation, :started_at,
7
+ :completed_at, :created_at, :last_modified_at, :expires_at,
8
+ :locale
9
+
10
+ attr_accessor :merchant_reference, :purchase_country, :purchase_currency
11
+
12
+ has_one :billing_address, Klarna::Checkout::Address
13
+ has_one :shipping_address, Klarna::Checkout::Address
14
+ has_one :cart, Klarna::Checkout::Cart
15
+ has_one :customer, Klarna::Checkout::Customer
16
+ has_one :merchant, Klarna::Checkout::Merchant
17
+ has_one :gui, Klarna::Checkout::Gui
18
+
19
+ def as_json
20
+ {
21
+ :merchant_reference => @merchant_reference,
22
+ :purchase_country => @purchase_country,
23
+ :purchase_currency => @purchase_currency,
24
+ :locale => @locale,
25
+ :cart => @cart.as_json,
26
+ :merchant => @merchant.as_json
27
+ }.reject do |k, v|
28
+ v.nil?
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,24 @@
1
+ require 'json'
2
+ require 'klarna/checkout/concerns/has_one'
3
+ require 'klarna/checkout/concerns/has_many'
4
+
5
+ module Klarna
6
+ module Checkout
7
+ class Resource
8
+ extend HasOne
9
+ extend HasMany
10
+
11
+ def initialize(args = {})
12
+ args.each_pair do |attr, value|
13
+ setter = "#{attr.to_s}="
14
+ self.send(setter, value) if respond_to?(setter)
15
+ end
16
+ end
17
+
18
+ def to_json
19
+ sanitized_json = self.as_json.reject { |k, v| v.nil? }
20
+ JSON.generate(sanitized_json)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,5 @@
1
+ module Klarna
2
+ module Checkout
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ describe "creating/reading order" do
4
+ around(:each) do |example|
5
+ VCR.use_cassette('create_order_spec') do
6
+ example.run
7
+ end
8
+ end
9
+
10
+ let(:client) do
11
+ Klarna::Checkout::Client.new \
12
+ shared_secret: 'foobar'
13
+ end
14
+
15
+ context "when I have created an order" do
16
+ let(:order) do
17
+ Klarna::Checkout::Order.new \
18
+ purchase_country: 'NO',
19
+ purchase_currency: 'NOK',
20
+ locale: 'nb-no',
21
+ cart: {
22
+ items: [{
23
+ reference: '1123581220325',
24
+ name: 'Widget',
25
+ quantity: 1,
26
+ unit_price: 666,
27
+ tax_rate: 2500
28
+ }]
29
+ },
30
+ merchant: {
31
+ id: '1337',
32
+ terms_uri: 'http://www.example.com/terms',
33
+ checkout_uri: 'http://www.example.com/checkout',
34
+ confirmation_uri: 'http://www.example.com/confirmation_uri',
35
+ push_uri: 'http://www.example.com/push'
36
+ }
37
+ end
38
+
39
+ before(:each) do
40
+ client.create_order(order)
41
+ end
42
+
43
+ describe "I should be able to fetch this order and read some attributes" do
44
+ let(:read_order) { client.read_order(order.id) }
45
+ subject { read_order }
46
+
47
+ it { should_not be_nil }
48
+
49
+ its(:id) { should eq order.id }
50
+ its(:status) { should eq 'checkout_incomplete' }
51
+
52
+ describe "cart" do
53
+ subject { read_order.cart }
54
+
55
+ its(:total_price_including_tax) { should eq 666 }
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe "reading order" do
4
+ around(:each) do |example|
5
+ VCR.use_cassette('read_order_spec') do
6
+ example.run
7
+ end
8
+ end
9
+
10
+ let(:client) do
11
+ Klarna::Checkout::Client.new \
12
+ shared_secret: 'foobar'
13
+ end
14
+
15
+ describe "I should be able to fetch an order and read its attributes" do
16
+ let(:read_order) { client.read_order('143F7EB92CD90B11C39E7220000') }
17
+ subject { read_order }
18
+
19
+ it { should_not be_nil }
20
+
21
+ its(:id) { should eq '143F7EB92CD90B11C39E7220000' }
22
+ its(:status) { should eq 'checkout_incomplete' }
23
+
24
+ describe "cart" do
25
+ subject { read_order.cart }
26
+
27
+ its(:total_price_including_tax) { should eq 666 }
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,85 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://checkout.testdrive.klarna.com/checkout/orders
6
+ body:
7
+ encoding: UTF-8
8
+ string: '{"purchase_country":"NO","purchase_currency":"NOK","locale":"nb-no","cart":{"items":[{"reference":"1123581220325","name":"Widget","quantity":1,"unit_price":666,"tax_rate":2500}]},"merchant":{"id":"1337","terms_uri":"http://www.example.com/terms","checkout_uri":"http://www.example.com/checkout","confirmation_uri":"http://www.example.com/confirmation_uri","push_uri":"http://www.example.com/push"}}'
9
+ headers:
10
+ User-Agent:
11
+ - Faraday v0.9.0
12
+ Authorization:
13
+ - Klarna gone
14
+ Content-Type:
15
+ - application/vnd.klarna.checkout.aggregated-order-v2+json
16
+ Accept:
17
+ - application/vnd.klarna.checkout.aggregated-order-v2+json, application/vnd.klarna.checkout.aggregated-order-v2+json
18
+ Accept-Encoding:
19
+ - ''
20
+ response:
21
+ status:
22
+ code: 201
23
+ message: Created
24
+ headers:
25
+ Server:
26
+ - MochiWeb/1.1 WebMachine/1.10.0 (never breaks eye contact)
27
+ Location:
28
+ - https://checkout.testdrive.klarna.com/checkout/orders/143F7EB92CD90B11C39E7220000
29
+ Date:
30
+ - Mon, 03 Feb 2014 13:24:07 GMT
31
+ Content-Type:
32
+ - application/vnd.klarna.checkout.aggregated-order-v2+json
33
+ Content-Length:
34
+ - '0'
35
+ Connection:
36
+ - keep-alive
37
+ body:
38
+ encoding: UTF-8
39
+ string: ''
40
+ http_version:
41
+ recorded_at: Mon, 03 Feb 2014 13:24:07 GMT
42
+ - request:
43
+ method: get
44
+ uri: https://checkout.testdrive.klarna.com/checkout/orders/143F7EB92CD90B11C39E7220000
45
+ body:
46
+ encoding: US-ASCII
47
+ string: ''
48
+ headers:
49
+ User-Agent:
50
+ - Faraday v0.9.0
51
+ Authorization:
52
+ - Klarna gone
53
+ Accept:
54
+ - application/vnd.klarna.checkout.aggregated-order-v2+json
55
+ Accept-Encoding:
56
+ - ''
57
+ response:
58
+ status:
59
+ code: 200
60
+ message: OK
61
+ headers:
62
+ Server:
63
+ - MochiWeb/1.1 WebMachine/1.10.0 (never breaks eye contact)
64
+ Pragma:
65
+ - no-cache
66
+ Date:
67
+ - Mon, 03 Feb 2014 13:24:08 GMT
68
+ Content-Type:
69
+ - application/vnd.klarna.checkout.aggregated-order-v2+json
70
+ Content-Length:
71
+ - '2060'
72
+ Cache-Control:
73
+ - max-age=0, no-cache, no-store
74
+ Connection:
75
+ - keep-alive
76
+ body:
77
+ encoding: UTF-8
78
+ string: '{"id":"143F7EB92CD90B11C39E7220000","purchase_country":"no","purchase_currency":"nok","locale":"nb-no","status":"checkout_incomplete","started_at":"2014-02-03T14:24:07+01:00","last_modified_at":"2014-02-03T14:24:07+01:00","cart":{"total_price_excluding_tax":532,"total_tax_amount":134,"total_price_including_tax":666,"items":[{"reference":"1123581220325","name":"Widget","quantity":1,"unit_price":666,"tax_rate":2500,"discount_rate":0,"type":"physical","total_price_including_tax":666,"total_price_excluding_tax":532,"total_tax_amount":134}]},"customer":{"type":"person"},"shipping_address":{"country":"no"},"billing_address":{"country":"no"},"gui":{"layout":"desktop","snippet":"<div
79
+ id=\"klarna-checkout-container\" style=\"overflow-x:\nhidden;\"><script type=\"text/javascript\">/*
80
+ <![CDATA[ */(function(w,k,i,d,u,n,c){w[k]=w[k]||function(){(w[k].q=w[k].q||[]).push(arguments)};w[k].config={container:w.document.getElementById(i),ORDER_URL:''https://checkout.testdrive.klarna.com/checkout/orders/143F7EB92CD90B11C39E7220000'',TESTDRIVE:true,AUTH_HEADER:''KlarnaCheckout
81
+ Pss54gM64IrvKxHMKUaA'',LAYOUT:''desktop'',LOCALE:''nb-no'',ORDER_STATUS:''checkout_incomplete'',MERCHANT_TAC_URI:''http://www.example.com/terms'',MERCHANT_TAC_TITLE:''test'',MERCHANT_NAME:''test'',GUI_OPTIONS:[],ALLOW_SEPARATE_SHIPPING_ADDRESS:false,PURCHASE_COUNTRY:''nor'',PURCHASE_CURRENCY:''nok'',DISALLOW_SKIP_NIN:false,BOOTSTRAP_SRC:u};n=d.createElement(''script'');c=d.getElementById(i);n.async=!0;n.src=u;c.insertBefore(n,c.firstChild);})(this,''_klarnaCheckout'',''klarna-checkout-container'',document,''https://checkout.testdrive.klarna.com/131022-064eb74/checkout.bootstrap.js'');/*
82
+ ]]> */</script><noscript>Please <a href=\"http://enable-javascript.com\">enable\nJavaScript</a>.</noscript></div>"},"options":{"allow_separate_shipping_address":false},"merchant":{"id":"1337","terms_uri":"http://www.example.com/terms","checkout_uri":"http://www.example.com/checkout","confirmation_uri":"http://www.example.com/confirmation_uri","push_uri":"http://www.example.com/push"}}'
83
+ http_version:
84
+ recorded_at: Mon, 03 Feb 2014 13:24:08 GMT
85
+ recorded_with: VCR 2.8.0
@@ -0,0 +1,47 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://checkout.testdrive.klarna.com/checkout/orders/143F7EB92CD90B11C39E7220000
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ User-Agent:
11
+ - Faraday v0.9.0
12
+ Authorization:
13
+ - Klarna gone
14
+ Accept:
15
+ - application/vnd.klarna.checkout.aggregated-order-v2+json
16
+ Accept-Encoding:
17
+ - ''
18
+ response:
19
+ status:
20
+ code: 200
21
+ message: OK
22
+ headers:
23
+ Server:
24
+ - MochiWeb/1.1 WebMachine/1.10.0 (never breaks eye contact)
25
+ Pragma:
26
+ - no-cache
27
+ Date:
28
+ - Tue, 04 Feb 2014 14:49:43 GMT
29
+ Content-Type:
30
+ - application/vnd.klarna.checkout.aggregated-order-v2+json
31
+ Content-Length:
32
+ - '2060'
33
+ Cache-Control:
34
+ - max-age=0, no-cache, no-store
35
+ Connection:
36
+ - keep-alive
37
+ body:
38
+ encoding: UTF-8
39
+ string: '{"id":"143F7EB92CD90B11C39E7220000","purchase_country":"no","purchase_currency":"nok","locale":"nb-no","status":"checkout_incomplete","started_at":"2014-02-03T14:24:07+01:00","last_modified_at":"2014-02-03T14:24:07+01:00","cart":{"total_price_excluding_tax":532,"total_tax_amount":134,"total_price_including_tax":666,"items":[{"reference":"1123581220325","name":"Widget","quantity":1,"unit_price":666,"tax_rate":2500,"discount_rate":0,"type":"physical","total_price_including_tax":666,"total_price_excluding_tax":532,"total_tax_amount":134}]},"customer":{"type":"person"},"shipping_address":{"country":"no"},"billing_address":{"country":"no"},"gui":{"layout":"desktop","snippet":"<div
40
+ id=\"klarna-checkout-container\" style=\"overflow-x:\nhidden;\"><script type=\"text/javascript\">/*
41
+ <![CDATA[ */(function(w,k,i,d,u,n,c){w[k]=w[k]||function(){(w[k].q=w[k].q||[]).push(arguments)};w[k].config={container:w.document.getElementById(i),ORDER_URL:''https://checkout.testdrive.klarna.com/checkout/orders/143F7EB92CD90B11C39E7220000'',TESTDRIVE:true,AUTH_HEADER:''KlarnaCheckout
42
+ Pss54gM64IrvKxHMKUaA'',LAYOUT:''desktop'',LOCALE:''nb-no'',ORDER_STATUS:''checkout_incomplete'',MERCHANT_TAC_URI:''http://www.example.com/terms'',MERCHANT_TAC_TITLE:''R\u00f8rkj\u00f8p
43
+ KCO'',MERCHANT_NAME:''R\u00f8rkj\u00f8p KCO'',GUI_OPTIONS:[],ALLOW_SEPARATE_SHIPPING_ADDRESS:false,PURCHASE_COUNTRY:''nor'',PURCHASE_CURRENCY:''nok'',DISALLOW_SKIP_NIN:false,BOOTSTRAP_SRC:u};n=d.createElement(''script'');c=d.getElementById(i);n.async=!0;n.src=u;c.insertBefore(n,c.firstChild);})(this,''_klarnaCheckout'',''klarna-checkout-container'',document,''https://checkout.testdrive.klarna.com/131022-064eb74/checkout.bootstrap.js'');/*
44
+ ]]> */</script><noscript>Please <a href=\"http://enable-javascript.com\">enable\nJavaScript</a>.</noscript></div>"},"options":{"allow_separate_shipping_address":false},"merchant":{"id":"1337","terms_uri":"http://www.example.com/terms","checkout_uri":"http://www.example.com/checkout","confirmation_uri":"http://www.example.com/confirmation_uri","push_uri":"http://www.example.com/push"}}'
45
+ http_version:
46
+ recorded_at: Tue, 04 Feb 2014 14:49:43 GMT
47
+ recorded_with: VCR 2.8.0
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+
3
+ describe Klarna::Checkout::Cart do
4
+ describe "attributes" do
5
+ it { should have_attribute(:total_price_including_tax) }
6
+ it { should have_attribute(:total_price_excluding_tax) }
7
+ it { should have_attribute(:total_tax_amount) }
8
+ end
9
+
10
+ describe "relations" do
11
+ it { should have_many(:items, as: Klarna::Checkout::CartItem) }
12
+ end
13
+
14
+ describe "#as_json" do
15
+ let(:cart) do
16
+ described_class.new \
17
+ total_price_including_tax: 250,
18
+ total_price_excluding_tax: 200,
19
+ total_tax_amount: 50,
20
+ items: [{
21
+ type: 'physical',
22
+ ean: '1123581220325',
23
+ reference: '1123581220325',
24
+ name: 'Widget',
25
+ uri: 'http://www.example.com/product-uri',
26
+ image_uri: 'http://www.example.com/product-image-uri',
27
+ quantity: 1,
28
+ unit_price: 250,
29
+ total_price_excluding_tax: 200,
30
+ total_tax_amount: 50,
31
+ total_price_including_tax: 250,
32
+ discount_rate: 0,
33
+ tax_rate: 2500
34
+ }]
35
+ end
36
+
37
+ let(:json_hash) { cart.as_json }
38
+ subject do
39
+ json_hash
40
+ end
41
+
42
+ its([:total_price_including_tax]) { should eq 250 }
43
+ its([:total_price_excluding_tax]) { should eq 200 }
44
+ its([:total_tax_amount]) { should eq 50 }
45
+
46
+ describe "items/0" do
47
+ subject { json_hash[:items][0] }
48
+
49
+ its([:type]) { should eq 'physical' }
50
+ its([:ean]) { should eq '1123581220325' }
51
+ its([:reference]) { should eq '1123581220325' }
52
+ its([:name]) { should eq 'Widget' }
53
+ its([:uri]) { should eq 'http://www.example.com/product-uri' }
54
+ its([:image_uri]) { should eq 'http://www.example.com/product-image-uri' }
55
+ its([:quantity]) { should eq 1 }
56
+ its([:unit_price]) { should eq 250 }
57
+ its([:total_price_excluding_tax]) { should eq 200 }
58
+ its([:total_tax_amount]) { should eq 50 }
59
+ its([:total_price_including_tax]) { should eq 250 }
60
+ its([:discount_rate]) { should eq 0 }
61
+ its([:tax_rate]) { should eq 2500 }
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+ require 'json'
3
+
4
+ describe Klarna::Checkout::Client do
5
+ describe ".new" do
6
+ subject do
7
+ described_class.new({
8
+ shared_secret: 'foobar'
9
+ })
10
+ end
11
+
12
+ its(:shared_secret) { should eq 'foobar' }
13
+ end
14
+
15
+ describe "#create_order" do
16
+ subject { described_class.new({shared_secret: 'foobar'}) }
17
+
18
+ let(:order) { double('Order', to_json: JSON.generate({ foo: "bar" }), :id= => true) }
19
+
20
+ it "sends a json representation of the object to Klarna" do
21
+ stub_request(:post, "https://checkout.testdrive.klarna.com/checkout/orders")
22
+ .to_return(headers: { 'Location' => 'https://checkout.testdrive.klarna.com/checkout/orders/143F7BC0A1090B11C39E7220000' })
23
+
24
+ subject.create_order(order)
25
+
26
+ assert_requested :post, "https://checkout.testdrive.klarna.com/checkout/orders",
27
+ :headers => {
28
+ # TODO: Investigate double definition in header
29
+ # 'Accept' => 'application/vnd.klarna.checkout.aggregated-order-v2+json',
30
+ 'Authorization' => 'Klarna dM+worqeBUs4UrOB3Jr/jSZWI39vP4LNw7NfDjGtW2w=',
31
+ 'Content-Type' => 'application/vnd.klarna.checkout.aggregated-order-v2+json',
32
+ },
33
+ :body => JSON.generate({ foo: "bar" }),
34
+ :times => 1
35
+ end
36
+ end
37
+
38
+ describe "#read_order" do
39
+ subject { described_class.new({shared_secret: 'foobar'}) }
40
+
41
+ it "uses the correct endpoint at klarna" do
42
+ stub_request(:get, "https://checkout.testdrive.klarna.com/checkout/orders/143F7BC0A1090B11C39E7220000")
43
+ .to_return(body: JSON.generate({ id: "143F7BC0A1090B11C39E7220000" }))
44
+
45
+ subject.read_order('143F7BC0A1090B11C39E7220000')
46
+
47
+ assert_requested :get, "https://checkout.testdrive.klarna.com/checkout/orders/143F7BC0A1090B11C39E7220000",
48
+ :headers => {
49
+ # TODO: Investigate double definition in header
50
+ # 'Accept' => 'application/vnd.klarna.checkout.aggregated-order-v2+json',
51
+ 'Authorization' => 'Klarna w6uP8Tcg6K2QR905Rms8iXTlksL6OD1KOWBxTK7wxPI=',
52
+ },
53
+ :times => 1
54
+ end
55
+ end
56
+
57
+ describe "#sign_payload" do
58
+ let(:client) { described_class.new(shared_secret: 'foobar') }
59
+
60
+ context "when request body is empty" do
61
+ subject { client.sign_payload }
62
+
63
+ it { should eq "w6uP8Tcg6K2QR905Rms8iXTlksL6OD1KOWBxTK7wxPI=" }
64
+ end
65
+
66
+ context "when request body has some content" do
67
+ subject { client.sign_payload('{"foo":"bar"}') }
68
+
69
+ it { should eq "dM+worqeBUs4UrOB3Jr/jSZWI39vP4LNw7NfDjGtW2w=" }
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,105 @@
1
+ require 'spec_helper'
2
+
3
+ describe Klarna::Checkout::Order do
4
+ describe ".initialize" do
5
+ subject do
6
+ described_class.new \
7
+ id: 1,
8
+ status: 'foo'
9
+ end
10
+
11
+ its(:id) { should eq 1 }
12
+ its(:status) { should eq 'foo' }
13
+ end
14
+
15
+ describe "attributes" do
16
+ it { should have_attribute(:id) } #, :readonly) }
17
+ it { should have_attribute(:merchant_reference) } #, :optional) }
18
+ it { should have_attribute(:purchase_country) } #, :mandatory) }
19
+ it { should have_attribute(:purchase_currency) } #, :mandatory) }
20
+ it { should have_attribute(:locale) } #, :mandatory) }
21
+ it { should have_attribute(:status) } #, :readonly) }
22
+ it { should have_attribute(:reference) } #, :readonly) }
23
+ it { should have_attribute(:reservation) } #, :readonly) }
24
+ it { should have_attribute(:started_at) } #, :readonly) }
25
+ it { should have_attribute(:completed_at) } #, :readonly) }
26
+ it { should have_attribute(:created_at) } #, :readonly) }
27
+ it { should have_attribute(:last_modified_at) } #, :readonly) }
28
+ it { should have_attribute(:expires_at) } #, :readonly) }
29
+ end
30
+
31
+ describe "relations" do
32
+ it { should have_one(:billing_address, as: Klarna::Checkout::Address) }
33
+ it { should have_one(:shipping_address, as: Klarna::Checkout::Address) }
34
+ it { should have_one(:cart, as: Klarna::Checkout::Cart) }
35
+ it { should have_one(:customer, as: Klarna::Checkout::Customer) }
36
+ it { should have_one(:merchant, as: Klarna::Checkout::Merchant) }
37
+ it { should have_one(:gui, as: Klarna::Checkout::Gui) }
38
+ end
39
+
40
+ describe "#as_json" do
41
+ let(:order) do
42
+ described_class.new \
43
+ merchant_reference: 'foo',
44
+ purchase_country: 'NO',
45
+ purchase_currency: 'NOK',
46
+ locale: 'nb-no',
47
+ cart: {
48
+ items: [{
49
+ reference: '1123581220325',
50
+ name: 'Widget',
51
+ quantity: 1,
52
+ unit_price: 666,
53
+ tax_rate: 2500
54
+ }]
55
+ },
56
+ merchant: {
57
+ id: '666666',
58
+ terms_uri: 'http://www.example.com/terms',
59
+ checkout_uri: 'http://www.example.com/checkout',
60
+ confirmation_uri: 'http://www.example.com/confirmation_uri',
61
+ push_uri: 'http://www.example.com/push'
62
+ }
63
+ end
64
+
65
+ let(:json_hash) { order.as_json }
66
+ subject do
67
+ json_hash
68
+ end
69
+
70
+ its([:merchant_reference]) { should eq 'foo' }
71
+ its([:purchase_country]) { should eq 'NO' }
72
+ its([:purchase_currency]) { should eq 'NOK' }
73
+ its([:locale]) { should eq 'nb-no' }
74
+
75
+ describe "cart/items/0" do
76
+ subject { json_hash[:cart][:items][0] }
77
+
78
+ its([:reference]) { should eq '1123581220325' }
79
+ its([:name]) { should eq 'Widget' }
80
+ its([:quantity]) { should eq 1 }
81
+ its([:unit_price]) { should eq 666 }
82
+ its([:tax_rate]) { should eq 2500 }
83
+ end
84
+
85
+ describe "merchant" do
86
+ subject { json_hash[:merchant] }
87
+
88
+ its([:id]) { should eq '666666' }
89
+ its([:terms_uri]) { should eq 'http://www.example.com/terms' }
90
+ its([:checkout_uri]) { should eq 'http://www.example.com/checkout' }
91
+ its([:confirmation_uri]) { should eq 'http://www.example.com/confirmation_uri' }
92
+ its([:push_uri]) { should eq 'http://www.example.com/push' }
93
+ end
94
+ end
95
+
96
+ describe "#to_json" do
97
+ it "bases it output on #as_json" do
98
+ subject.stub(:as_json) { { foo: "bar" } }
99
+ subject.to_json.should eq JSON.generate({ foo: "bar" })
100
+
101
+ subject.stub(:as_json) { { bar: "foo" } }
102
+ subject.to_json.should eq JSON.generate({ bar: "foo" })
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,5 @@
1
+ require 'klarna/checkout/client'
2
+
3
+ describe Klarna::Checkout::VERSION do
4
+ it { should eq '0.0.1' }
5
+ end
@@ -0,0 +1,24 @@
1
+ require 'klarna/checkout'
2
+
3
+ require 'webmock/rspec'
4
+ require 'vcr'
5
+
6
+ # require 'shoulda/matchers'
7
+
8
+ VCR.configure do |c|
9
+ c.cassette_library_dir = File.expand_path("../fixtures/vcr_cassettes", __FILE__)
10
+ c.hook_into :webmock # or :fakeweb
11
+ end
12
+
13
+ RSpec.configure do |config|
14
+ config.treat_symbols_as_metadata_keys_with_true_values = true
15
+ config.run_all_when_everything_filtered = true
16
+
17
+ config.filter_run :focus => true
18
+ config.mock_with :rspec
19
+
20
+ # config.order = "random"
21
+ end
22
+
23
+ Dir[File.expand_path("../shared/**/*.rb", __FILE__)].each { |f| require f }
24
+ Dir[File.expand_path("../support/**/*.rb", __FILE__)].each { |f| require f }
@@ -0,0 +1,34 @@
1
+ require 'rspec/expectations'
2
+
3
+ RSpec::Matchers.define :have_attribute do |attr_name| # , type|
4
+ match do |subject|
5
+ attr_name = attr_name.to_s
6
+
7
+ subject.should respond_to("#{attr_name}")
8
+ subject.should respond_to("#{attr_name}=")
9
+
10
+ # case type
11
+ # when :readonly
12
+ # # expect {
13
+ # subject.public_send("#{attr_name}=")
14
+ # # }.to raise_error(NoMethodError)
15
+ # when :mandatory
16
+ # # subject.should validate_presence_of(attr_name)
17
+ # when :optional
18
+ # # subject.should_not validate_presence_of(attr_name)
19
+ # else
20
+ # raise "Please supply :readonly, :mandatory or :optional as second "+
21
+ # "argument to have_attribute matcher."
22
+ # end
23
+
24
+ # unless type == :readonly
25
+ # expect {
26
+ # subject.public_send("#{attr_name}=", 'new_value')
27
+ # }.to change(subject, attr_name).to('new_value')
28
+ # end
29
+ end
30
+
31
+ # failure_message_for_should do |klass|
32
+ # "expected #{klass.class.to_s} to have #{type.to_s} attribute #{attr_name}"
33
+ # end
34
+ end
@@ -0,0 +1,17 @@
1
+ require 'rspec/expectations'
2
+
3
+ RSpec::Matchers.define :have_many do |attr_name, options|
4
+ match do |subject|
5
+ subject.should respond_to(attr_name)
6
+ subject.should respond_to("#{attr_name}=")
7
+
8
+ if options[:as]
9
+ subject.public_send("#{attr_name}=", [{}])
10
+ subject.public_send(attr_name).first.class.should eq options[:as]
11
+ end
12
+ end
13
+
14
+ failure_message_for_should do |klass|
15
+ "expected #{klass.inspect} to have has_many-association #{attr_name}"
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ require 'rspec/expectations'
2
+
3
+ RSpec::Matchers.define :have_one do |attr_name, options|
4
+ match do |subject|
5
+ subject.should respond_to(attr_name)
6
+ subject.should respond_to("#{attr_name}=")
7
+
8
+ if options[:as]
9
+ subject.public_send("#{attr_name}=", {})
10
+ subject.public_send(attr_name).class.should eq options[:as]
11
+ end
12
+ end
13
+
14
+ failure_message_for_should do |klass|
15
+ "expected #{klass.inspect} to have has_one-association #{attr_name}"
16
+ end
17
+ end
metadata ADDED
@@ -0,0 +1,230 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: klarna-checkout
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Theodor Tonum
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activemodel
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: guard
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: guard-rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: webmock
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: vcr
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: shoulda-matchers
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ description: Ruby Wrapper for Klarna Checkout Rest API
154
+ email:
155
+ - theodor@tonum.no
156
+ executables: []
157
+ extensions: []
158
+ extra_rdoc_files: []
159
+ files:
160
+ - .gitignore
161
+ - .rspec
162
+ - Gemfile
163
+ - Guardfile
164
+ - LICENSE.txt
165
+ - README.md
166
+ - Rakefile
167
+ - klarna-checkout.gemspec
168
+ - lib/klarna/checkout.rb
169
+ - lib/klarna/checkout/address.rb
170
+ - lib/klarna/checkout/cart.rb
171
+ - lib/klarna/checkout/cart_item.rb
172
+ - lib/klarna/checkout/client.rb
173
+ - lib/klarna/checkout/concerns/has_many.rb
174
+ - lib/klarna/checkout/concerns/has_one.rb
175
+ - lib/klarna/checkout/customer.rb
176
+ - lib/klarna/checkout/gui.rb
177
+ - lib/klarna/checkout/merchant.rb
178
+ - lib/klarna/checkout/order.rb
179
+ - lib/klarna/checkout/resource.rb
180
+ - lib/klarna/checkout/version.rb
181
+ - spec/acceptance/create_order_spec.rb
182
+ - spec/acceptance/read_order_spec.rb
183
+ - spec/fixtures/vcr_cassettes/create_order_spec.yml
184
+ - spec/fixtures/vcr_cassettes/read_order_spec.yml
185
+ - spec/lib/klarna/checkout/cart_spec.rb
186
+ - spec/lib/klarna/checkout/client_spec.rb
187
+ - spec/lib/klarna/checkout/order_spec.rb
188
+ - spec/lib/klarna/checkout/version_spec.rb
189
+ - spec/spec_helper.rb
190
+ - spec/support/matchers/have_attribute.rb
191
+ - spec/support/matchers/have_many.rb
192
+ - spec/support/matchers/have_one.rb
193
+ homepage: ''
194
+ licenses:
195
+ - MIT
196
+ metadata: {}
197
+ post_install_message:
198
+ rdoc_options: []
199
+ require_paths:
200
+ - lib
201
+ required_ruby_version: !ruby/object:Gem::Requirement
202
+ requirements:
203
+ - - '>='
204
+ - !ruby/object:Gem::Version
205
+ version: '0'
206
+ required_rubygems_version: !ruby/object:Gem::Requirement
207
+ requirements:
208
+ - - '>='
209
+ - !ruby/object:Gem::Version
210
+ version: '0'
211
+ requirements: []
212
+ rubyforge_project:
213
+ rubygems_version: 2.1.5
214
+ signing_key:
215
+ specification_version: 4
216
+ summary: '...'
217
+ test_files:
218
+ - spec/acceptance/create_order_spec.rb
219
+ - spec/acceptance/read_order_spec.rb
220
+ - spec/fixtures/vcr_cassettes/create_order_spec.yml
221
+ - spec/fixtures/vcr_cassettes/read_order_spec.yml
222
+ - spec/lib/klarna/checkout/cart_spec.rb
223
+ - spec/lib/klarna/checkout/client_spec.rb
224
+ - spec/lib/klarna/checkout/order_spec.rb
225
+ - spec/lib/klarna/checkout/version_spec.rb
226
+ - spec/spec_helper.rb
227
+ - spec/support/matchers/have_attribute.rb
228
+ - spec/support/matchers/have_many.rb
229
+ - spec/support/matchers/have_one.rb
230
+ has_rdoc: