fortnox 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +7 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/README +15 -0
- data/Rakefile +1 -0
- data/fortnox.gemspec +27 -0
- data/lib/fortnox.rb +11 -0
- data/lib/fortnox/api.rb +43 -0
- data/lib/fortnox/customer.rb +23 -0
- data/lib/fortnox/errors.rb +3 -0
- data/lib/fortnox/invoice.rb +32 -0
- data/lib/fortnox/version.rb +3 -0
- data/spec/fixtures/invoice.yml +23 -0
- data/spec/integration/customer_spec.rb +22 -0
- data/spec/integration/invoice_spec.rb +38 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/unit/api_spec.rb +38 -0
- data/spec/unit/customer_spec.rb +23 -0
- data/spec/unit/invoice_spec.rb +28 -0
- metadata +163 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/README
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# Fortnox Ruby Wrapper
|
2
|
+
Based on HTTParty
|
3
|
+
For Invoicing, Customers
|
4
|
+
|
5
|
+
## Testing
|
6
|
+
* RSpec
|
7
|
+
* Fakeweb/VCR?
|
8
|
+
* guard start
|
9
|
+
|
10
|
+
## Poor mans docs
|
11
|
+
|
12
|
+
* Som det fungerar nu är det Fortnox::Invoice.create .update .destroy som gäller
|
13
|
+
* Du får ett ID tillbaka när det gick bra annars false.
|
14
|
+
* ID behövs användas för att exempelvis uppdatera.
|
15
|
+
* Värt att notera är att när du lägger till en kontakt på en faktura är det inte ID du får när du skapar en kontakt som gäller, ID då är kundnr.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/fortnox.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "fortnox/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "fortnox"
|
7
|
+
s.version = Fortnox::VERSION
|
8
|
+
s.authors = ["Jonas Arnklint", "Kevin Sjöberg"]
|
9
|
+
s.email = ["jonas@fkw.se", "kev.sjoberg@gmail.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Handle invoices and customers through the Fortnox API}
|
12
|
+
s.description = %q{Handle invoices and customers through the Fortnox API}
|
13
|
+
|
14
|
+
s.rubyforge_project = "fortnox"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_development_dependency "rspec"
|
22
|
+
s.add_development_dependency "vcr"
|
23
|
+
s.add_development_dependency "webmock"
|
24
|
+
|
25
|
+
s.add_runtime_dependency "httparty"
|
26
|
+
s.add_runtime_dependency "gyoku"
|
27
|
+
end
|
data/lib/fortnox.rb
ADDED
data/lib/fortnox/api.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
module Fortnox
|
2
|
+
class API
|
3
|
+
include HTTParty
|
4
|
+
|
5
|
+
base_uri 'https://kund2.fortnox.se/ext/'
|
6
|
+
format :xml
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def establish_connection(opts={})
|
10
|
+
@@token = opts[:token] || ENV['fortnox_token']
|
11
|
+
@@database = opts[:database] || ENV['fortnox_database']
|
12
|
+
@@query_parameters = connection
|
13
|
+
end
|
14
|
+
|
15
|
+
def connection
|
16
|
+
{ :token => @@token, :db => @@database }
|
17
|
+
end
|
18
|
+
|
19
|
+
def run(method, call, attributes={})
|
20
|
+
self.query_parameters = attributes[:query] if attributes[:query]
|
21
|
+
self.send(method, "/#{call.to_s}.php", {
|
22
|
+
:query => query_parameters,
|
23
|
+
:body => {:xml => build_xml(attributes)}
|
24
|
+
})
|
25
|
+
end
|
26
|
+
|
27
|
+
def query_parameters
|
28
|
+
@@query_parameters
|
29
|
+
end
|
30
|
+
|
31
|
+
def query_parameters=(params={})
|
32
|
+
@@query_parameters = query_parameters.merge(params)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def build_xml(attributes)
|
38
|
+
attributes.delete(:query) if attributes[:query]
|
39
|
+
@@xml = Gyoku.xml(attributes)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Fortnox
|
2
|
+
class Customer < API
|
3
|
+
class << self
|
4
|
+
def create(attributes={})
|
5
|
+
attributes = attributes.reject { |k,v| k == :id } if attributes[:id]
|
6
|
+
|
7
|
+
response = run(:post, :set_contact, with_root(attributes))
|
8
|
+
response['result'] ? response['result']['id'].to_i : false
|
9
|
+
end
|
10
|
+
|
11
|
+
def update(attributes={})
|
12
|
+
response = run :post, :set_contact, with_root(attributes)
|
13
|
+
response['result'] ? response['result']['id'].to_i : false
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def with_root(attributes)
|
19
|
+
{:contact => attributes}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Fortnox
|
2
|
+
class Invoice < API
|
3
|
+
class << self
|
4
|
+
def create(attributes={})
|
5
|
+
attributes = attributes.reject { |k,v| k == :id } if attributes[:id]
|
6
|
+
|
7
|
+
response = run :post, :set_invoice, with_root(attributes)
|
8
|
+
if response['result']
|
9
|
+
return response['result']['id'].to_i
|
10
|
+
else
|
11
|
+
raise Error, response.body
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def update(attributes={})
|
16
|
+
response = run :post, :set_invoice, with_root(attributes)
|
17
|
+
response['result'] ? response['result']['id'].to_i : false
|
18
|
+
end
|
19
|
+
|
20
|
+
def destroy(id)
|
21
|
+
response = run :post, :set_invoice_cancel, { :query => { :id => id } }
|
22
|
+
response['result'] ? response['result'].to_i : false
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def with_root(attributes)
|
28
|
+
{ :invoice => attributes }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
id: 1
|
2
|
+
tdate: '2012-01-04'
|
3
|
+
ddate: '2012-02-03'
|
4
|
+
edate: '2012-02-03'
|
5
|
+
ourref: 'Foo Bar'
|
6
|
+
yourref: 'Bar Foo'
|
7
|
+
roundoff: 1.0
|
8
|
+
freight: 0.0
|
9
|
+
totalvat: 50.0
|
10
|
+
total: 250.0
|
11
|
+
contact:
|
12
|
+
id: 1
|
13
|
+
name: 'Example AB'
|
14
|
+
address: 'Example street'
|
15
|
+
city: 'Example'
|
16
|
+
zip: '123 45'
|
17
|
+
pricelist: 'A'
|
18
|
+
invoicerows:
|
19
|
+
invoicerow:
|
20
|
+
descr: 'Sample product'
|
21
|
+
price: 100.0
|
22
|
+
amount: 2.0
|
23
|
+
vat: 25.0
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Fortnox
|
4
|
+
describe Customer do
|
5
|
+
before(:each) { API.establish_connection }
|
6
|
+
|
7
|
+
it "should create customer and return it's id" do
|
8
|
+
VCR.use_cassette('customer/create') do
|
9
|
+
customer_id = Customer.create(fixtures(:invoice)["contact"])
|
10
|
+
customer_id.should be_a(Integer)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should update customer given by id and return it's id" do
|
15
|
+
VCR.use_cassette('customer/update') do
|
16
|
+
customer_id = Customer.update(fixtures(:invoice)["contact"].merge(:name => 'Example Customer'))
|
17
|
+
customer_id.should be_a(Integer)
|
18
|
+
customer_id.should eq(1)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Fortnox
|
4
|
+
describe Invoice do
|
5
|
+
before(:each) { API.establish_connection }
|
6
|
+
|
7
|
+
it "should raise error on invalid invoice creation" do
|
8
|
+
VCR.use_cassette('invoice/create_invalid') do
|
9
|
+
lambda {
|
10
|
+
Invoice.create(fixtures(:invoice).delete('tdate'))
|
11
|
+
}.should raise_error(Error)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should create invoice and return it's id" do
|
16
|
+
VCR.use_cassette('invoice/create') do
|
17
|
+
invoice_no = Invoice.create(fixtures(:invoice))
|
18
|
+
invoice_no.should be_a(Integer)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should update invoice given by id and return it's id" do
|
23
|
+
VCR.use_cassette('invoice/update') do
|
24
|
+
invoice_no = Invoice.update(fixtures(:invoice).merge(:ourref => 'Foo Foo'))
|
25
|
+
invoice_no.should be_a(Integer)
|
26
|
+
invoice_no.should eq(1)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should destroy invoice given by id and return it's id" do
|
31
|
+
VCR.use_cassette('invoice/destroy') do
|
32
|
+
invoice_no = Invoice.destroy(1)
|
33
|
+
invoice_no.should be_a(Integer)
|
34
|
+
invoice_no.should eq(1)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require "fortnox"
|
2
|
+
require "yaml"
|
3
|
+
require "vcr"
|
4
|
+
|
5
|
+
|
6
|
+
def fixtures(fixture)
|
7
|
+
@@fixtures ||= load_fixtures
|
8
|
+
@@fixtures[fixture]
|
9
|
+
end
|
10
|
+
|
11
|
+
def load_fixtures
|
12
|
+
fixtures = {}
|
13
|
+
|
14
|
+
Dir['spec/fixtures/*.yml'].each do |file|
|
15
|
+
name = File.basename(file, File.extname(file)).to_sym
|
16
|
+
fixtures[name] = YAML::load(File.open(file).read)
|
17
|
+
end
|
18
|
+
|
19
|
+
fixtures
|
20
|
+
end
|
21
|
+
|
22
|
+
VCR.config do |c|
|
23
|
+
c.default_cassette_options = {:match_requests_on => [:method, :uri, :body]}
|
24
|
+
c.cassette_library_dir = 'spec/fixtures/cassettes'
|
25
|
+
c.stub_with :webmock
|
26
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Fortnox
|
4
|
+
describe API do
|
5
|
+
let(:query_params) { {:token => 'foo', :db => 'bar'} }
|
6
|
+
|
7
|
+
before :each do
|
8
|
+
API.establish_connection({:token => 'foo', :database => 'bar'})
|
9
|
+
API.stub(:post)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "can establish a connection" do
|
13
|
+
API.connection.should eq(query_params)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "can make post request" do
|
17
|
+
attributes = {:foo => 'bar'}
|
18
|
+
|
19
|
+
API.should_receive(:post).with('/test.php', {
|
20
|
+
:query => query_params,
|
21
|
+
:body => {:xml => '<foo>bar</foo>'}
|
22
|
+
})
|
23
|
+
|
24
|
+
API.run(:post, 'test', attributes)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "can make post request with query parameters" do
|
28
|
+
attributes = {:foo => 'bar', :query => {:id => 1}}
|
29
|
+
|
30
|
+
API.should_receive(:post).with('/test.php', {
|
31
|
+
:query => query_params.merge(attributes[:query]),
|
32
|
+
:body => {:xml => '<foo>bar</foo>'}
|
33
|
+
})
|
34
|
+
|
35
|
+
API.run(:post, 'test', attributes)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module Fortnox
|
4
|
+
describe Customer do
|
5
|
+
let(:attributes) { {:id => 1, :name => 'Example AB'} }
|
6
|
+
|
7
|
+
it "makes a post request and dismisses specified id" do
|
8
|
+
Customer.stub(:run) { { 'result' => { 'id' => '2' } } }
|
9
|
+
|
10
|
+
Customer.should_receive(:run).with(:post, :set_contact, { :contact => attributes.reject { |k, v| k == :id } })
|
11
|
+
customer_number = Customer.create(attributes)
|
12
|
+
|
13
|
+
customer_number.should_not eq(attributes[:id])
|
14
|
+
end
|
15
|
+
|
16
|
+
it "makes a post request and preserves specified id" do
|
17
|
+
Customer.stub(:run) { {'result' => {'id' => '1'}} }
|
18
|
+
|
19
|
+
Customer.should_receive(:run).with(:post, :set_contact, {:contact => attributes})
|
20
|
+
customer_number = Customer.update(attributes)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module Fortnox
|
4
|
+
describe Invoice do
|
5
|
+
let(:attributes) { {:id => 1, :ourref => 'Foo Bar', :yourref => 'Bar Foo'} }
|
6
|
+
|
7
|
+
before :each do
|
8
|
+
Invoice.stub(:run) { {'result' => {'id' => '2'}} }
|
9
|
+
end
|
10
|
+
|
11
|
+
it "makes a post request and dismisses specified id" do
|
12
|
+
Invoice.should_receive(:run).with(:post, :set_invoice, {:invoice => attributes.reject { |k,v| k == :id }})
|
13
|
+
invoice_number = Invoice.create(attributes)
|
14
|
+
invoice_number.should_not eq(attributes[:id])
|
15
|
+
end
|
16
|
+
|
17
|
+
it "makes a post request and preserves specified id" do
|
18
|
+
Invoice.should_receive(:run).with(:post, :set_invoice, {:invoice => attributes})
|
19
|
+
Invoice.update(attributes)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "makes a post request with query parameter id" do
|
23
|
+
Invoice.stub(:run) { {'result' => '2'} }
|
24
|
+
Invoice.should_receive(:run).with(:post, :set_invoice_cancel, {:query => {:id => 2}})
|
25
|
+
Invoice.destroy(2)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fortnox
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Jonas Arnklint
|
14
|
+
- "Kevin Sj\xC3\xB6berg"
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2012-03-20 00:00:00 +01:00
|
20
|
+
default_executable:
|
21
|
+
dependencies:
|
22
|
+
- !ruby/object:Gem::Dependency
|
23
|
+
name: rspec
|
24
|
+
prerelease: false
|
25
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ">="
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
hash: 3
|
31
|
+
segments:
|
32
|
+
- 0
|
33
|
+
version: "0"
|
34
|
+
type: :development
|
35
|
+
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: vcr
|
38
|
+
prerelease: false
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
hash: 3
|
45
|
+
segments:
|
46
|
+
- 0
|
47
|
+
version: "0"
|
48
|
+
type: :development
|
49
|
+
version_requirements: *id002
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: webmock
|
52
|
+
prerelease: false
|
53
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
hash: 3
|
59
|
+
segments:
|
60
|
+
- 0
|
61
|
+
version: "0"
|
62
|
+
type: :development
|
63
|
+
version_requirements: *id003
|
64
|
+
- !ruby/object:Gem::Dependency
|
65
|
+
name: httparty
|
66
|
+
prerelease: false
|
67
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
hash: 3
|
73
|
+
segments:
|
74
|
+
- 0
|
75
|
+
version: "0"
|
76
|
+
type: :runtime
|
77
|
+
version_requirements: *id004
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: gyoku
|
80
|
+
prerelease: false
|
81
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
hash: 3
|
87
|
+
segments:
|
88
|
+
- 0
|
89
|
+
version: "0"
|
90
|
+
type: :runtime
|
91
|
+
version_requirements: *id005
|
92
|
+
description: Handle invoices and customers through the Fortnox API
|
93
|
+
email:
|
94
|
+
- jonas@fkw.se
|
95
|
+
- kev.sjoberg@gmail.com
|
96
|
+
executables: []
|
97
|
+
|
98
|
+
extensions: []
|
99
|
+
|
100
|
+
extra_rdoc_files: []
|
101
|
+
|
102
|
+
files:
|
103
|
+
- .gitignore
|
104
|
+
- .rspec
|
105
|
+
- Gemfile
|
106
|
+
- README
|
107
|
+
- Rakefile
|
108
|
+
- fortnox.gemspec
|
109
|
+
- lib/fortnox.rb
|
110
|
+
- lib/fortnox/api.rb
|
111
|
+
- lib/fortnox/customer.rb
|
112
|
+
- lib/fortnox/errors.rb
|
113
|
+
- lib/fortnox/invoice.rb
|
114
|
+
- lib/fortnox/version.rb
|
115
|
+
- spec/fixtures/invoice.yml
|
116
|
+
- spec/integration/customer_spec.rb
|
117
|
+
- spec/integration/invoice_spec.rb
|
118
|
+
- spec/spec_helper.rb
|
119
|
+
- spec/unit/api_spec.rb
|
120
|
+
- spec/unit/customer_spec.rb
|
121
|
+
- spec/unit/invoice_spec.rb
|
122
|
+
has_rdoc: true
|
123
|
+
homepage: ""
|
124
|
+
licenses: []
|
125
|
+
|
126
|
+
post_install_message:
|
127
|
+
rdoc_options: []
|
128
|
+
|
129
|
+
require_paths:
|
130
|
+
- lib
|
131
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
132
|
+
none: false
|
133
|
+
requirements:
|
134
|
+
- - ">="
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
hash: 3
|
137
|
+
segments:
|
138
|
+
- 0
|
139
|
+
version: "0"
|
140
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
141
|
+
none: false
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
hash: 3
|
146
|
+
segments:
|
147
|
+
- 0
|
148
|
+
version: "0"
|
149
|
+
requirements: []
|
150
|
+
|
151
|
+
rubyforge_project: fortnox
|
152
|
+
rubygems_version: 1.6.2
|
153
|
+
signing_key:
|
154
|
+
specification_version: 3
|
155
|
+
summary: Handle invoices and customers through the Fortnox API
|
156
|
+
test_files:
|
157
|
+
- spec/fixtures/invoice.yml
|
158
|
+
- spec/integration/customer_spec.rb
|
159
|
+
- spec/integration/invoice_spec.rb
|
160
|
+
- spec/spec_helper.rb
|
161
|
+
- spec/unit/api_spec.rb
|
162
|
+
- spec/unit/customer_spec.rb
|
163
|
+
- spec/unit/invoice_spec.rb
|