Permalink
Browse files

Fixes based on feedback from Klarna tech preparing for first public r…

…elease.
  • Loading branch information...
grimen committed Oct 16, 2011
1 parent 7d585a4 commit 5add30a63d9154d7c25350d5fc9360091704a386
View
@@ -10,6 +10,14 @@ h2. What is Klarna?
Sweden (SE), Norway (NO), Denmark (DK), Finland (FI), Germany (DE), Netherlands (NL).
+h2. Implementation/Background
+
+This gem was developed as a semi-1:1 implementation of the corresponding API implementations provided by Klarna (with a few simple justifications and heavily refactored methods). Klarnas official implementations were not implemented using OO patterns and as their implementation was changing very often without any notice/versioning I kept it simple as possible.
+
+Since Klarna 2.0 was released they'va refactored their implementations a lot which makes it a good idea to review this implementation as well. Like stated in the TODO I had a clean classy DSL in mind.
+
+This is not a complete implementation, but not far from it and enough for most use cases - a few of the more advanced API methods needs a review/revisit (code disabled now).
+
h2. Setup
Install the gem:
@@ -123,7 +131,7 @@ This gem was developed for our own requirements at "Merchii":http://github.com/m
h2. To-do
-This is not a complete implementation, but not far from it though. I had bigger plans way back when we wrote this, but since I assume Klarna will release a completely new API soon (_Klarna 2.0_ which I assume will be REST API?) - we're not sure we will bother to "finish" the planned features for the current XML-RPC API. Time will tell. For more details, see the "TODO":https://github.com/merchii/klarna-ruby/blob/master/TODO.
+See the "TODO":https://github.com/merchii/klarna-ruby/blob/master/TODO.
h2. License
View
14 TODO
@@ -1,15 +1,16 @@
== CURRENT
-x [feature]: Implement the last missing Invoicing methods
------
-* [feature]: Review/Implement something like: our_settype_integer, our_strip_string, our_settype_string (consider one generic method, e.g. parse(:price, value) - all validation/masking/casting in one place)
-* [feature]: Ensure valid string format/stripping (e.g. SSN, etc)
-* [feature]: Ensure correct params datatypes are submitted (validation - consider generic method)
+x [issue]: Test the invoice activation in a proper way - not allowed in the Klarna 2.0 API (for some weird reason...)
== HIGH-PRIO
+* [feature]: Review/Implement something like: our_settype_integer, our_strip_string, our_settype_string (consider one generic method, e.g. parse(:price, value) - all validation/masking/casting in one place)
+* [feature]: Ensure valid string format/stripping (e.g. SSN, etc) using regular expressions
+* [feature]: Compare implementation with Klarna's new API 2.0
+* [feature]: Ensure correct params datatypes are submitted (validation - consider generic method)
+* [feature]: Klarna::DSL - wrapper DSL for less sucky integrations
* [feature]: Implement #get_pclasses method to export pclasses as hash (and maybe export to YAML?)
* [feature]: ActiveMerchant-integration (fork ActiveMerchant and add klarna as new gateway with "klarna-ruby" as dependency)
@@ -18,11 +19,12 @@ x [feature]: Implement the last missing Invoicing methods
* [feature]: Finalize the rest of the specs for already implemented methods, commented out currently.
* [feature]: Implement Reservation methods
-* [feature]: Klarna::DSL - wrapper DSL for less sucky integrations
* [feature]: Bring back "examples/web" - probably not working at all now.
* [feature]: Rack middleware?
== MAYBE
* [feature]: Mock XML-responses by default to avoid live API calls, but allow live calls using ENV['REMOTE]=true
+
+ https://github.com/myronmarston/vcr
View
@@ -9,7 +9,7 @@ class Client < ::XMLRPC::Client
include ::Klarna::API::Methods
- attr_accessor :store_id,
+ attr_accessor :store_id,
:store_secret,
:mode,
:timeout,
@@ -79,15 +79,15 @@ def ssl?
alias :use_ssl? :ssl?
def protocol
- @protocol ||= ::Klarna::API::END_POINT[self.mode][:protocol]
+ @protocol = ::Klarna::API::END_POINT[self.mode][:protocol]
end
def host
- @host ||= ::Klarna::API::END_POINT[self.mode][:host]
+ @host = ::Klarna::API::END_POINT[self.mode][:host]
end
def port
- @port ||= ::Klarna::API::END_POINT[self.mode][:port]
+ @port = ::Klarna::API::END_POINT[self.mode][:port]
end
def endpoint_uri
@@ -10,17 +10,17 @@ module Constants
END_POINT = {
:test => {
:protocol => 'http',
- :host => 'payment.klarna.com',
+ :host => 'payment-beta.klarna.com',
:port => 80
},
:production => {
- :protocol => 'http',
+ :protocol => 'https',
:host => 'payment.klarna.com',
- :port => 80
+ :port => 443
}
}.freeze
- PROTOCOL_ENCODING = 'iso-8859-1'.freeze # ['UTF-8', 'ISO-8859-1', 'US-ASCII'].freeze
+ PROTOCOL_ENCODING = 'iso-8859-1'.freeze # NOTE: New API supports: ['UTF-8', 'ISO-8859-1', 'US-ASCII'].freeze
PROTOCOL_VERSION = '4.0'.freeze
# -----------------------------------------------------------------------
@@ -5,7 +5,7 @@ module API
module Methods
module CostCalculations
- # Purpose: Obtain pcalss values from Klarna.
+ # Purpose: Obtain pclass values from Klarna.
#
# == Note:
#
@@ -12,7 +12,7 @@ module Invoicing
# Create an invoice.
#
- def add_invoice(store_user_id, order_id, goods_list, shipping_fee,
+ def add_invoice(store_user_id, order_id, articles, shipping_fee,
handling_fee, shipment_type, pno, first_name, last_name, address, client_ip,
currency, country, language, pno_encoding, pclass = nil, annual_salary = nil,
password = nil, ready_date = nil, comment = nil, rand_string = nil, new_password = nil, flags = nil)
@@ -23,13 +23,14 @@ def add_invoice(store_user_id, order_id, goods_list, shipping_fee,
pno_encoding = ::Klarna::API.id_for(:pno_format, pno_encoding)
pclass = pclass ? ::Klarna::API.id_for(:pclass, pclass) : -1
flags = ::Klarna::API.parse_flags(:INVOICE, flags)
+ articles = Array.wrap(articles).compact
params = [
self.store_id,
store_user_id,
- self.digest(goods_list.collect { |g| g[:goods][:title] }, :store_id => false),
+ self.digest(articles.collect { |g| g[:goods][:title] }, :store_id => false),
order_id,
- goods_list,
+ articles,
shipping_fee,
shipment_type,
handling_fee,
@@ -70,6 +71,7 @@ def add_invoice(store_user_id, order_id, goods_list, shipping_fee,
def activate_invoice(invoice_no, articles = nil)
# TODO: Parse/Validate invoice_no as :integer
# TODO: Parse/Valdiate articles as array of articles
+ articles = Array.wrap(articles).compact
params = [
self.store_id,
@@ -79,7 +81,7 @@ def activate_invoice(invoice_no, articles = nil)
# Only partly?
if articles.present?
params << articles
- params << self.digest(invoice_no, articles.collect { |a| a.join(':') }.join(':'))
+ params << self.digest(invoice_no, articles.collect { |a| [a[:goods][:artno], a[:qty]].join(':') }.join(':'))
method = :activate_part
else
params << self.digest(invoice_no)
@@ -107,36 +109,37 @@ def delete_invoice(invoice_no)
# Give discounts for invoices.
#
def return_amount(invoice_no, amount, vat)
- # params = [
- # self.store_id,
- # invoice_no,
- # amount,
- # vat,
- # self.digest(invoice_no)
- # ]
- # self.call(:return_amount, *params)
- raise NotImplementedError
+ params = [
+ self.store_id,
+ invoice_no,
+ amount,
+ vat,
+ self.digest(invoice_no)
+ ]
+ self.call(:return_amount, *params) # raise NotImplementedError
end
# Return a invoice - optionally only partly.
#
def credit_invoice(invoice_no, credit_id, articles = nil)
- # params = [
- # self.store_id,
- # invoice_no,
- # credit_id,
- # ]
- # # Only partly?
- # if articles.present?
- # params << articles
- # params << self.digest(invoice_no, articles.collect { |a| a.join(':') }.join(':'))
- # method = :credit_part
- # else
- # params << self.digest(invoice_no)
- # method = :credit_invoice
- # end
- # self.call(method, *params)
- raise NotImplementedError
+ articles = Array.wrap(articles).compact
+
+ params = [
+ self.store_id,
+ invoice_no,
+ credit_id,
+ ]
+
+ if articles.present? # Only partly?
+ params << articles
+ params << self.digest(invoice_no, articles.collect { |a| [a[:goods][:artno], a[:qty]].join(':') }.join(':'))
+ method = :credit_part
+ else
+ params << self.digest(invoice_no)
+ method = :credit_invoice
+ end
+
+ self.call(method, *params)
end
# Send an active invoice to the customer via e-mail.
@@ -253,6 +256,13 @@ def invoice_address(invoice_no)
#
def invoice_amount(invoice_no, articles = nil)
# TODO: Parse/Validate invoice_no as integer
+ articles = Array.wrap(articles).compact
+ artnos =
+ if articles.first.respond_to?(:key?) && articles.first.key?(:qty) && articles.first.key?(:artno)
+ articles
+ else
+ articles.collect { |a| {:artno => a[:goods][:artno], :qty => a[:qty]} }
+ end
params = [
self.store_id,
@@ -261,8 +271,8 @@ def invoice_amount(invoice_no, articles = nil)
# Only partly?
if articles.present?
- params << articles
- params << self.digest(invoice_no, articles.collect { |a| a.join(':') }.join(':'))
+ params << artnos
+ params << self.digest(invoice_no, artnos.collect { |an| [an[:artno], an[:qty]].join(':') }.join(':'))
method = :invoice_part_amount
else
params << self.digest(invoice_no)
@@ -109,13 +109,12 @@ def make_goods(quantity, article_no, title, price, vat, discount = nil, flags =
# Check if a user has an account.
#
def has_account?(pno, pno_encoding)
- # params = [
- # self.store_id,
- # self.digest(pno),
- # pno_encoding
- # ]
- # self.call(:has_account, *params)
- raise NotImplementedError
+ params = [
+ self.store_id,
+ self.digest(pno),
+ pno_encoding
+ ]
+ self.call(:has_account, *params)
end
end
View
@@ -1,5 +1,5 @@
# encoding: utf-8
module Klarna
- VERSION = '0.1.2'
+ VERSION = '0.1.3'
end
@@ -3,7 +3,7 @@
describe Klarna::API::Methods::CostCalculations do
- # TODO: Mock responses.
+ # TODO: Mock responses using VCR.
before do
valid_credentials!
Oops, something went wrong.

0 comments on commit 5add30a

Please sign in to comment.