sk_sdk 0.2.2 → 0.3.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.
- data/.gitignore +2 -3
- data/README.rdoc +1 -1
- data/ci/Gemfile_ar2 +11 -0
- data/lib/sk_sdk/README.rdoc +25 -23
- data/lib/sk_sdk/ar_patches/ar2/base.rb +7 -1
- data/lib/sk_sdk/ar_patches/ar3/base.rb +7 -1
- data/lib/sk_sdk/version.rb +1 -1
- data/spec/resources_spec_helper.rb +6 -9
- data/spec/sk_sdk/base_spec.rb +7 -7
- data/spec/sk_sdk/resources/contacts_spec.rb +100 -0
- data/spec/sk_sdk/resources/credit_note_spec.rb +12 -25
- data/spec/sk_sdk/resources/invoice_spec.rb +212 -136
- data/spec/sk_sdk/resources/payment_spec.rb +84 -0
- metadata +6 -4
- data/spec/sk_sdk/resources/clients_spec.rb +0 -98
data/.gitignore
CHANGED
data/README.rdoc
CHANGED
data/ci/Gemfile_ar2
ADDED
data/lib/sk_sdk/README.rdoc
CHANGED
@@ -64,28 +64,28 @@ remember we only support HTTPS:
|
|
64
64
|
=>
|
65
65
|
https://my_company.salesking.eu/api
|
66
66
|
|
67
|
-
For convenience we check if your url ends in /api and add if you forgot it!
|
67
|
+
For convenience we check if your url ends in /api and add it if you forgot it!
|
68
68
|
|
69
69
|
Create a single class
|
70
70
|
|
71
71
|
require 'sk_sdk/base'
|
72
72
|
|
73
|
-
class
|
73
|
+
class Contact < SK::SDK::Base;end
|
74
74
|
|
75
75
|
# connection using BasicAuth
|
76
|
-
|
76
|
+
Contact.set_connection( {:site => 'https://my_sub.salesking.eu/api',
|
77
77
|
:user => 'my-users@login-email.com',
|
78
78
|
:password => 'password' })
|
79
79
|
|
80
|
-
|
81
|
-
|
82
|
-
|
80
|
+
contact = Contact.new(:last_name => 'Ding', :organisation => "Carpenters Inc.", :type=>'Client')
|
81
|
+
contact.first_name = "Bill"
|
82
|
+
contact.save
|
83
83
|
|
84
84
|
Create multiple classes at once
|
85
85
|
|
86
86
|
require 'sk_sdk/base'
|
87
87
|
module; King; end
|
88
|
-
%w[
|
88
|
+
%w[Contact Invoice Product LineItem SubTotalItem].each do |model|
|
89
89
|
eval "class King::#{model} < SK::SDK::Base;end"
|
90
90
|
end
|
91
91
|
|
@@ -105,14 +105,14 @@ Create multiple classes at once
|
|
105
105
|
|
106
106
|
== Quick start - Basic's
|
107
107
|
|
108
|
-
To give it quick shot, point your browser to my-account.salesking.eu/api/
|
108
|
+
To give it quick shot, point your browser to my-account.salesking.eu/api/contacts.json
|
109
109
|
(while beeing logged in) and you will see the JSON in the response.
|
110
110
|
This is an example of a GET-request issued by your browser.
|
111
111
|
|
112
112
|
Or use CURL, if you prefer the command line:
|
113
113
|
|
114
114
|
curl -u your@login-mail.com:password \
|
115
|
-
https://demo.salesking.eu/
|
115
|
+
https://demo.salesking.eu/api/contacts
|
116
116
|
|
117
117
|
Request Method overview:
|
118
118
|
GET => read
|
@@ -130,12 +130,12 @@ A list of resources:
|
|
130
130
|
GET xy.salesking.eu/api/invoices
|
131
131
|
|
132
132
|
A single resource
|
133
|
-
GET xy.salesking.eu/invoices/:id
|
133
|
+
GET xy.salesking.eu/api/invoices/:id
|
134
134
|
|
135
135
|
Returned JSON data for a listings, abbreviated:
|
136
136
|
{
|
137
|
-
"
|
138
|
-
{ "
|
137
|
+
"contacts": [ # array of resources => contacts
|
138
|
+
{ "contact": { # a single resource
|
139
139
|
"number": "0800013", ..
|
140
140
|
"links":{} #links for the resource
|
141
141
|
}, ...
|
@@ -147,9 +147,9 @@ Returned JSON data for a listings, abbreviated:
|
|
147
147
|
"per_page": 30
|
148
148
|
},
|
149
149
|
"links": { # links for the collection
|
150
|
-
"prev": "/api/
|
151
|
-
"next": "/api/
|
152
|
-
"self": "/api/
|
150
|
+
"prev": "/api/contacts?page=0",
|
151
|
+
"next": "/api/contacts?page=2",
|
152
|
+
"self": "/api/contacts?page=1"
|
153
153
|
},
|
154
154
|
}
|
155
155
|
|
@@ -167,15 +167,15 @@ Available filters are defined in each json-schema's instances link ({see invoice
|
|
167
167
|
# q-wildcard search in several fields
|
168
168
|
GET xy.salesking.eu/api/invoices?filter[q]=0815&per_page=40
|
169
169
|
|
170
|
-
# find all documents for one or more
|
171
|
-
GET xy.salesking.eu/api/documents?filter[
|
170
|
+
# find all documents for one or more contacts
|
171
|
+
GET xy.salesking.eu/api/documents?filter[contact_ids]=:id,:id
|
172
172
|
|
173
173
|
=== POST / Create
|
174
174
|
|
175
175
|
To create a resource make a POST request containing the json for a single resource.
|
176
176
|
|
177
177
|
Header: content-type application/json
|
178
|
-
POST https://my-sub.salesking.eu/invoices.json
|
178
|
+
POST https://my-sub.salesking.eu/api/invoices.json
|
179
179
|
|
180
180
|
{"invoice": {
|
181
181
|
"title": "Your service subscription 2011",
|
@@ -194,12 +194,13 @@ To create a resource make a POST request containing the json for a single resour
|
|
194
194
|
=== PUT / Update
|
195
195
|
|
196
196
|
Header: content-type application/json
|
197
|
-
PUT /api/
|
197
|
+
PUT /api/contacts/:id
|
198
198
|
{
|
199
|
-
'
|
199
|
+
'contact':
|
200
200
|
{
|
201
201
|
'gender':'male',
|
202
|
-
'first_name': "Andrew"
|
202
|
+
'first_name': "Andrew",
|
203
|
+
'type': 'Client'
|
203
204
|
}
|
204
205
|
}
|
205
206
|
|
@@ -207,10 +208,11 @@ To create a resource make a POST request containing the json for a single resour
|
|
207
208
|
|
208
209
|
A DELETE request to a resource url deletes and returns the deleted object:
|
209
210
|
|
210
|
-
DELETE https://demo.salesking.eu/
|
211
|
+
DELETE https://demo.salesking.eu/api/contacts/:id
|
211
212
|
|
212
213
|
== Hints on ActiveResource
|
213
214
|
|
215
|
+
* It sucks!
|
214
216
|
* Most of the magic is coming from ActiveResource so you should read {its README and code}[https://github.com/rails/rails/tree/master/activeresource]
|
215
217
|
* This client does NOT rely on parsing the JSON Schema, since ActiveResource(AR) creates the Getter/Setter methods.
|
216
218
|
* We added some patches for AR to fix JSON parsing issues, due to our nesting.
|
@@ -226,7 +228,7 @@ command-line http client) for testing. And of course any http library supporting
|
|
226
228
|
http-basic-auth.
|
227
229
|
|
228
230
|
* {Getting started tutorial}[http://dev.blog.salesking.eu/api/]
|
229
|
-
* {SalesKing API Schema}[https://github.com/salesking/sk_api_schema]
|
231
|
+
* {SalesKing API Browser}[http://sk-api-browser.herokuapp.com/] - {SalesKing API Schema}[https://github.com/salesking/sk_api_schema]
|
230
232
|
* {Chrome cRest extension}[https://chrome.google.com/extensions/detail/baedhhmoaooldchehjhlpppaieoglhml]
|
231
233
|
* {Poster FF-Plugin - make HTTP request}[https://addons.mozilla.org/en-US/firefox/addon/2691/] (you must be logged into SalesKing)
|
232
234
|
* {JSONView FF-Plugin - view json in firefox}[https://addons.mozilla.org/de/firefox/addon/10869/]
|
@@ -20,10 +20,16 @@ module ActiveResource
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
# override ARes method to parse only the
|
23
|
+
# override ARes method to parse only the object part
|
24
24
|
def load_attributes_from_response(response)
|
25
25
|
if response['Content-Length'] != "0" && response.body.strip.size > 0
|
26
26
|
load( self.class.format.decode(response.body)[self.class.element_name] )
|
27
|
+
if self.respond_to?(:items)
|
28
|
+
# move double nested items up
|
29
|
+
new_items = []
|
30
|
+
self.items.each { |item| new_items << item.attributes.first[1] }
|
31
|
+
self.items = new_items
|
32
|
+
end
|
27
33
|
end
|
28
34
|
end
|
29
35
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module ActiveResource
|
2
2
|
# Overridden methods to suit SalesKing's nested json format
|
3
|
-
# only valid for AR 3.1
|
3
|
+
# only valid for AR 3.1+
|
4
4
|
# In the future might add a custom format class, see base.format
|
5
5
|
class Base
|
6
6
|
|
@@ -8,6 +8,12 @@ module ActiveResource
|
|
8
8
|
def load_attributes_from_response(response)
|
9
9
|
if (response['Transfer-Encoding'] == 'chunked' || (!response['Content-Length'].blank? && response['Content-Length'] != "0")) && !response.body.nil? && response.body.strip.size > 0
|
10
10
|
load( self.class.format.decode(response.body)[self.class.element_name] )
|
11
|
+
#fix double nested items .. active resource SUCKS soooo bad
|
12
|
+
if self.respond_to?(:items)
|
13
|
+
new_items = []
|
14
|
+
self.items.each { |item| new_items << item.attributes.first[1] }
|
15
|
+
self.items = new_items
|
16
|
+
end
|
11
17
|
@persisted = true
|
12
18
|
end
|
13
19
|
end
|
data/lib/sk_sdk/version.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
# create all classes and set their connection
|
3
|
-
%w[
|
3
|
+
%w[Contact Address CreditNote Invoice Product LineItem User Payment Email].each do |model|
|
4
4
|
eval "class #{model} < SK::SDK::Base;end" unless Object.const_defined?(model)
|
5
5
|
end
|
6
6
|
SK::SDK::Base.set_connection basic_auth_settings
|
@@ -8,7 +8,7 @@ SK::SDK::Base.set_connection basic_auth_settings
|
|
8
8
|
def sk_available?
|
9
9
|
begin
|
10
10
|
User.get(:current)
|
11
|
-
rescue
|
11
|
+
rescue
|
12
12
|
return false
|
13
13
|
end
|
14
14
|
end
|
@@ -23,13 +23,10 @@ def kick_existing(obj, number)
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def delete_test_data(doc, client)
|
26
|
-
doc.
|
26
|
+
if doc.status !='draft'
|
27
|
+
doc.status ='draft'
|
28
|
+
doc.save
|
29
|
+
end
|
27
30
|
client.destroy
|
28
|
-
lambda {
|
29
|
-
doc = Invoice.find(doc.id)
|
30
|
-
}.should raise_error(ActiveResource::ResourceNotFound)
|
31
|
-
lambda {
|
32
|
-
client = Client.find(client.id)
|
33
|
-
}.should raise_error(ActiveResource::ResourceNotFound)
|
34
31
|
end
|
35
32
|
|
data/spec/sk_sdk/base_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'resources_spec_helper'
|
3
3
|
|
4
|
-
class
|
4
|
+
class Contact < SK::SDK::Base;end
|
5
5
|
# create objects in King namespace
|
6
6
|
module KingTester; end
|
7
7
|
%w[Invoice Product].each do |model|
|
@@ -11,7 +11,7 @@ end
|
|
11
11
|
describe SK::SDK::Base, "make new class" do
|
12
12
|
|
13
13
|
it "should create class" do
|
14
|
-
c =
|
14
|
+
c = Contact.new
|
15
15
|
c.first_name = 'herbert' # implicit setter
|
16
16
|
c.first_name.should == 'herbert' # implicit getter
|
17
17
|
end
|
@@ -25,17 +25,17 @@ describe SK::SDK::Base, "make new class" do
|
|
25
25
|
end
|
26
26
|
|
27
27
|
it "should have properties as attributes" do
|
28
|
-
c =
|
28
|
+
c = Contact.new :some_field => ''
|
29
29
|
c.attributes.should == {"some_field"=>""}
|
30
30
|
end
|
31
31
|
|
32
32
|
it "should create save method" do
|
33
|
-
c =
|
33
|
+
c = Contact.new
|
34
34
|
c.respond_to?(:save).should be_true
|
35
35
|
end
|
36
36
|
|
37
37
|
it "should have new_record?" do
|
38
|
-
c =
|
38
|
+
c = Contact.new
|
39
39
|
c.new_record?.should be_true
|
40
40
|
i = KingTester::Invoice.new
|
41
41
|
i.new_record?.should be_true
|
@@ -46,9 +46,9 @@ describe SK::SDK::Base, "make new class" do
|
|
46
46
|
it "should allow multiple parameters in initializer" do
|
47
47
|
expect {
|
48
48
|
if ActiveResource::VERSION::MAJOR == 3 && ActiveResource::VERSION::MINOR > 0
|
49
|
-
|
49
|
+
Contact.new({ :first_name => 'herbert' }, true)
|
50
50
|
else
|
51
|
-
|
51
|
+
Contact.new({ :first_name => 'herbert' })
|
52
52
|
end
|
53
53
|
}.should_not raise_error(ArgumentError)
|
54
54
|
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'resources_spec_helper'
|
2
|
+
|
3
|
+
unless sk_available?
|
4
|
+
puts "Sorry cannot connect to your SalesKing server, skipping real connections tests. Please check connection settings in spec_helper"
|
5
|
+
else
|
6
|
+
|
7
|
+
describe Contact, "with real connection" do
|
8
|
+
|
9
|
+
before :all do
|
10
|
+
@contact = Contact.new(:organisation=>'from testing API2', :type => 'Lead')
|
11
|
+
@contact.save
|
12
|
+
end
|
13
|
+
|
14
|
+
after :all do
|
15
|
+
#delete test contact
|
16
|
+
@contact.destroy
|
17
|
+
lambda {
|
18
|
+
contact = Contact.find(@contact.id)
|
19
|
+
}.should raise_error(ActiveResource::ResourceNotFound)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should save" do
|
23
|
+
c = Contact.new :organisation=>"Rack'n Roll", :type => 'Client'
|
24
|
+
c.save.should be_true
|
25
|
+
c.id.should_not be_empty
|
26
|
+
c.number.should_not be_empty
|
27
|
+
c.destroy
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should fail create a contact" do
|
31
|
+
contact = Contact.new(:organisation=>'from testing API2', :type => 'Client')
|
32
|
+
contact.bank_iban = 'safasf'
|
33
|
+
contact.save.should == false
|
34
|
+
contact.errors.count.should == 1
|
35
|
+
contact.errors.full_messages.should == ["Bank iban is invalid"]
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should find a single contact" do
|
39
|
+
contact = Contact.find(@contact.id)
|
40
|
+
contact.organisation.should == @contact.organisation
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should find contacts" do
|
44
|
+
contacts = Contact.find(:all)
|
45
|
+
contacts.should_not be_empty
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
describe Contact, "with addresses" do
|
51
|
+
|
52
|
+
before :all do
|
53
|
+
#setup test contact to work with
|
54
|
+
@contact = Contact.new(:organisation=>'Second from testing API2',
|
55
|
+
:type => 'Client',
|
56
|
+
:addresses => [{ :zip => '50374', :city => 'Cologne' }] )
|
57
|
+
|
58
|
+
@contact.save
|
59
|
+
end
|
60
|
+
|
61
|
+
after :all do
|
62
|
+
@contact.destroy
|
63
|
+
lambda {
|
64
|
+
contact = Contact.find(@contact.id)
|
65
|
+
}.should raise_error(ActiveResource::ResourceNotFound)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should create an address" do
|
69
|
+
@contact.addresses.length.should == 1
|
70
|
+
@contact.addresses.first.zip.should == '50374'
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should edit an address" do
|
74
|
+
@contact.addresses.length.should == 1
|
75
|
+
# puts @contact.addresses.inspect
|
76
|
+
@contact.addresses[0].zip = '40001'
|
77
|
+
@contact.save
|
78
|
+
@contact.addresses.length.should == 1
|
79
|
+
@contact.addresses.first.zip.should == '40001'
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should add an address" do
|
83
|
+
cnt_before = @contact.addresses.length
|
84
|
+
adr = Address.new( { :zip => '37700', :city => 'Cologne' } )
|
85
|
+
@contact.addresses << adr
|
86
|
+
@contact.save
|
87
|
+
@contact.addresses.length.should == cnt_before+1
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should destroy an address" do
|
91
|
+
cnt_before = @contact.addresses.length
|
92
|
+
@contact.addresses.last._destroy = 1
|
93
|
+
@contact.save
|
94
|
+
@contact.reload
|
95
|
+
@contact.addresses.length.should == cnt_before-1
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
end
|
@@ -8,25 +8,16 @@ else
|
|
8
8
|
|
9
9
|
before :all do
|
10
10
|
#setup test doc to work with
|
11
|
-
|
12
|
-
@
|
13
|
-
@client.save.should be_true
|
11
|
+
@contact = Contact.new(:type=>'Supplier', :organisation=>'Credit Note API-Tester')
|
12
|
+
@contact.save.should be_true
|
14
13
|
@doc = CreditNote.new()
|
15
14
|
@doc.title = 'A Document from the API'
|
16
|
-
@doc.
|
15
|
+
@doc.contact_id = @contact.id
|
17
16
|
@doc.save.should be_true
|
18
17
|
end
|
19
18
|
|
20
19
|
after :all do
|
21
|
-
|
22
|
-
@doc.destroy
|
23
|
-
@client.destroy
|
24
|
-
lambda {
|
25
|
-
doc = CreditNote.find(@doc.id)
|
26
|
-
}.should raise_error(ActiveResource::ResourceNotFound)
|
27
|
-
lambda {
|
28
|
-
client = Client.find(@client.id)
|
29
|
-
}.should raise_error(ActiveResource::ResourceNotFound)
|
20
|
+
delete_test_data @doc, @contact
|
30
21
|
end
|
31
22
|
|
32
23
|
it "should create a doc and use default before after text" do
|
@@ -41,7 +32,7 @@ else
|
|
41
32
|
doc.save.should == true
|
42
33
|
doc2 = CreditNote.new(:number=>'001')
|
43
34
|
doc2.save.should == false
|
44
|
-
doc2.errors.count.should ==
|
35
|
+
doc2.errors.count.should == 1
|
45
36
|
if doc2.errors.respond_to? :on # TODO kick with AR 2.3
|
46
37
|
doc2.errors.on(:number).should == "has already been taken"
|
47
38
|
else
|
@@ -71,7 +62,7 @@ else
|
|
71
62
|
doc1.save.should == true
|
72
63
|
@doc.number = '002'
|
73
64
|
@doc.save.should == false
|
74
|
-
@doc.errors.count.should ==
|
65
|
+
@doc.errors.count.should == 1
|
75
66
|
if @doc.errors.respond_to? :on # TODO kick with AR 2.3
|
76
67
|
@doc.errors.on(:number).should == "has already been taken"
|
77
68
|
else
|
@@ -84,27 +75,23 @@ else
|
|
84
75
|
describe CreditNote, "with line items" do
|
85
76
|
|
86
77
|
before :all do
|
87
|
-
@
|
88
|
-
@
|
78
|
+
@contact =Contact.new(:type=>'Supplier', :organisation=>'Credit Note API-Tester')
|
79
|
+
@contact.save.should be_true
|
89
80
|
#setup test doc to work with
|
90
|
-
@doc = CreditNote.new :
|
81
|
+
@doc = CreditNote.new :contact_id => @contact.id,
|
91
82
|
:line_items =>[{ :position=>1, :description => 'Pork Chops',
|
92
83
|
:quantity => 12, :price_single =>'10.00'}]
|
93
84
|
@doc.save.should be_true
|
94
85
|
end
|
95
86
|
|
96
87
|
after :all do
|
97
|
-
@
|
98
|
-
# @doc.destroy
|
99
|
-
lambda {
|
100
|
-
doc = CreditNote.find(@doc.id)
|
101
|
-
}.should raise_error(ActiveResource::ResourceNotFound)
|
88
|
+
delete_test_data @doc, @contact
|
102
89
|
end
|
103
90
|
|
104
91
|
it "should create a line item" do
|
105
92
|
@doc.line_items.length.should == 1
|
106
93
|
@doc.line_items.first.description.should == 'Pork Chops'
|
107
|
-
@doc.
|
94
|
+
@doc.gross_total.should == 120.0
|
108
95
|
end
|
109
96
|
|
110
97
|
it "should edit line item" do
|
@@ -120,7 +107,7 @@ else
|
|
120
107
|
@doc.line_items << item
|
121
108
|
@doc.save
|
122
109
|
@doc.line_items.length.should == 2
|
123
|
-
@doc.
|
110
|
+
@doc.gross_total.should == 220.0
|
124
111
|
# @doc.line_items[0].zip = '40001'
|
125
112
|
# @doc.line_items.[1].zip.should == '40001'
|
126
113
|
end
|
@@ -1,169 +1,245 @@
|
|
1
|
-
#require 'spec_helper'
|
2
1
|
require 'resources_spec_helper'
|
3
2
|
|
4
3
|
unless sk_available?
|
5
|
-
puts
|
4
|
+
puts 'Sorry cannot connect to your SalesKing server, skipping real connections tests. Please check connection settings in spec_helper'
|
6
5
|
else
|
7
6
|
|
8
|
-
describe Invoice
|
7
|
+
describe Invoice do
|
9
8
|
|
10
|
-
|
11
|
-
@client = Client.new(:organisation=>'Invoice API-Tester')
|
12
|
-
@client.save.should be_true
|
13
|
-
@doc = Invoice.new()
|
14
|
-
@doc.title = 'A Document from the API'
|
15
|
-
@doc.client_id = @client.id
|
16
|
-
@doc.save.should be_true
|
17
|
-
end
|
9
|
+
context 'in general' do
|
18
10
|
|
19
|
-
|
20
|
-
|
21
|
-
|
11
|
+
before :all do
|
12
|
+
@contact = Contact.new(:type=>'Client', :organisation=>'Invoice API-Tester')
|
13
|
+
@contact.save.should be_true
|
14
|
+
@doc = Invoice.new()
|
15
|
+
@doc.title = 'A Document from the API'
|
16
|
+
@doc.contact_id = @contact.id
|
17
|
+
@doc.save.should be_true
|
18
|
+
end
|
22
19
|
|
23
|
-
|
24
|
-
|
25
|
-
|
20
|
+
after :all do
|
21
|
+
delete_test_data(@doc, @contact)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should find a doc' do
|
25
|
+
doc = Invoice.find(@doc.id)
|
26
|
+
doc.title.should == @doc.title
|
27
|
+
end
|
26
28
|
end
|
27
|
-
end
|
28
29
|
|
29
|
-
|
30
|
+
context 'new' do
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
32
|
+
before :all do
|
33
|
+
@contact = Contact.new(:type=>'Client', :organisation=>'Invoice API-Tester')
|
34
|
+
@contact.save.should be_true
|
35
|
+
end
|
36
|
+
after :all do
|
37
|
+
@contact.destroy
|
38
|
+
end
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
40
|
+
it 'should create a doc' do
|
41
|
+
doc = Invoice.new
|
42
|
+
doc.title = 'A Document from the API'
|
43
|
+
doc.notes_before = 'Your shiny new invoice [number]'
|
44
|
+
doc.notes_after = 'Please pay me'
|
45
|
+
doc.contact_id = @contact.id
|
46
|
+
doc.save.should be_true
|
47
|
+
doc.errors.should be_empty
|
48
|
+
doc.new?.should be_false
|
49
|
+
doc.notes_before.should == 'Your shiny new invoice [number]'
|
50
|
+
doc.destroy
|
51
|
+
end
|
51
52
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
53
|
+
it 'should create a doc with default before after texts' do
|
54
|
+
doc = Invoice.new
|
55
|
+
doc.title = 'A Document from the API'
|
56
|
+
doc.contact_id = @contact.id
|
57
|
+
doc.save
|
58
|
+
doc.errors.should be_empty
|
59
|
+
doc.new?.should be_false
|
60
|
+
doc.notes_before.should_not be_empty
|
61
|
+
doc.destroy
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should fail create a doc without unique number' do
|
65
|
+
# if a test failed this invoice might still be present so try to delete
|
66
|
+
kick_existing(Invoice, '001')
|
67
|
+
doc = Invoice.new(:number=>'001')
|
68
|
+
doc.save.should == true
|
69
|
+
doc2 = Invoice.new(:number=>'001')
|
70
|
+
doc2.save.should == false
|
71
|
+
doc2.errors.count.should == 1
|
72
|
+
if doc2.errors.respond_to? :on
|
73
|
+
doc2.errors.on(:number).should == 'has already been taken'
|
74
|
+
else
|
75
|
+
doc2.errors[:number].should == ['has already been taken']
|
76
|
+
end
|
77
|
+
doc.destroy
|
78
|
+
end
|
62
79
|
|
63
|
-
it "should fail create a doc without unique number" do
|
64
|
-
# if a test failed this invoice might still be present so try to delete
|
65
|
-
kick_existing(Invoice, '001')
|
66
|
-
doc = Invoice.new(:number=>'001')
|
67
|
-
doc.save.should == true
|
68
|
-
doc2 = Invoice.new(:number=>'001')
|
69
|
-
doc2.save.should == false
|
70
|
-
doc2.errors.count.should == 2
|
71
|
-
if doc2.errors.respond_to? :on
|
72
|
-
doc2.errors.on(:number).should == "has already been taken"
|
73
|
-
else
|
74
|
-
doc2.errors[:number].should == ["has already been taken"]
|
75
|
-
end
|
76
|
-
doc.destroy
|
77
80
|
end
|
78
81
|
|
79
|
-
|
82
|
+
describe 'edit' do
|
80
83
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
@doc.save.should be_true
|
93
|
-
end
|
84
|
+
before :all do
|
85
|
+
#setup test doc to work with
|
86
|
+
# create client
|
87
|
+
@contact = Contact.new(:type=>'Client', :organisation=>'Invoice API-Tester')
|
88
|
+
@contact.save.should be_true
|
89
|
+
@doc = Invoice.new
|
90
|
+
@doc.title = 'A Document from the API'
|
91
|
+
@doc.notes_before = 'Your invoice [number]'
|
92
|
+
@doc.contact_id = @contact.id
|
93
|
+
@doc.save.should be_true
|
94
|
+
end
|
94
95
|
|
95
|
-
|
96
|
-
|
97
|
-
|
96
|
+
after :all do
|
97
|
+
delete_test_data(@doc, @contact)
|
98
|
+
end
|
98
99
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
100
|
+
it 'should edit a doc' do
|
101
|
+
old_lock_version = @doc.lock_version
|
102
|
+
@doc.notes_before.should == 'Your invoice [number]'
|
103
|
+
@doc.notes_before = 'You will recieve the amout of:'
|
104
|
+
@doc.notes_after = 'Payment made to you bank Account'
|
105
|
+
@doc.title = 'Changed doc title'
|
105
106
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
107
|
+
@doc.save.should be_true
|
108
|
+
@doc.lock_version.should > old_lock_version # because save returns the data
|
109
|
+
@doc.notes_before.should == 'You will recieve the amout of:'
|
110
|
+
end
|
110
111
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
112
|
+
it 'should fail edit with wrong number' do
|
113
|
+
kick_existing(Invoice, '002')
|
114
|
+
doc1 = Invoice.new(:number=>'002')
|
115
|
+
doc1.save.should == true
|
116
|
+
@doc.number = '002'
|
117
|
+
@doc.save.should == false
|
118
|
+
@doc.errors.count.should == 1
|
119
|
+
if @doc.errors.respond_to? :on # TODO kick with AR 2.3
|
120
|
+
@doc.errors.on(:number).should == 'has already been taken'
|
121
|
+
else
|
122
|
+
@doc.errors[:number].should == ['has already been taken']
|
123
|
+
end
|
124
|
+
doc1.destroy
|
125
|
+
end
|
124
126
|
end
|
125
|
-
end
|
126
127
|
|
127
|
-
describe
|
128
|
+
describe 'with line items' do
|
128
129
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
130
|
+
before :all do
|
131
|
+
@contact = Contact.new(:type=>'Client', :organisation=>'Credit Note API-Tester')
|
132
|
+
@contact.save.should be_true
|
133
|
+
#setup test doc to work with
|
134
|
+
@doc = Invoice.new(:contact_id => @contact.id,
|
135
|
+
:line_items => [{ :position=>1, :description => 'Pork Chops',
|
136
|
+
:quantity => 12, :price_single =>'10.00' }] )
|
137
|
+
@doc.save.should be_true
|
138
|
+
end
|
138
139
|
|
139
|
-
|
140
|
-
|
141
|
-
|
140
|
+
after :all do
|
141
|
+
delete_test_data(@doc, @contact)
|
142
|
+
end
|
142
143
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
144
|
+
it 'should create a line item' do
|
145
|
+
@doc.line_items.length.should == 1
|
146
|
+
@doc.line_items.first.description.should == 'Pork Chops'
|
147
|
+
@doc.gross_total.should == 120.0
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'should edit line item' do
|
151
|
+
@doc.line_items[0].description = 'Egg Sandwich'
|
152
|
+
@doc.save
|
153
|
+
@doc.line_items.length.should == 1
|
154
|
+
@doc.line_items.first.description.should == 'Egg Sandwich'
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'should add line item' do
|
158
|
+
item = LineItem.new( { :position=>2, :description => 'Goat-Pie', :price_single => 10, :quantity=>10} )
|
159
|
+
product = Product.new(:name=>'Eis am Stiel', :price => 1.50, :tax=>19, :description => 'Mmmhh lecker Eis')
|
160
|
+
product.save.should be_true
|
161
|
+
item1 = LineItem.new( { :position=>3, :use_product => 1, :product_id=> product.id, :quantity => 10 } )
|
162
|
+
@doc.line_items << item
|
163
|
+
@doc.line_items << item1
|
164
|
+
@doc.save
|
165
|
+
@doc.line_items.length.should == 3
|
166
|
+
@doc.net_total.should == 235.0
|
167
|
+
@doc.gross_total.should == 237.85
|
168
|
+
end
|
148
169
|
|
149
|
-
it "should edit line item" do
|
150
|
-
@doc.line_items[0].description = 'Egg Sandwich'
|
151
|
-
@doc.save
|
152
|
-
@doc.line_items.length.should == 1
|
153
|
-
@doc.line_items.first.description.should == 'Egg Sandwich'
|
154
170
|
end
|
155
171
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
172
|
+
describe 'with items of different type' do
|
173
|
+
before :all do
|
174
|
+
@contact = Contact.new(:type=>'Client', :organisation=>'Credit Note API-Tester')
|
175
|
+
@contact.save.should be_true
|
176
|
+
@doc = Invoice.new(:contact_id => @contact.id)
|
177
|
+
end
|
178
|
+
|
179
|
+
after :all do
|
180
|
+
delete_test_data(@doc, @contact)
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'should create items from array' do
|
184
|
+
@doc.items = [
|
185
|
+
{ :position=>1, :name => 'Pork Chops', :quantity => 12, :price_single =>'10.00', :type=>'LineItem' },
|
186
|
+
{ :position=>2, :name => 'Pork Sub Total', :type=>'SubTotalItem' },
|
187
|
+
{ :position=>2, :name => 'Yummi Beef', :type=>'DividerItem' },
|
188
|
+
{ :position=>3, :name => 'Beef Jerky', :description=> 'Jaw Breaker',:quantity => 1, :price_single =>'10.00', :type=>'LineItem' }
|
189
|
+
]
|
190
|
+
@doc.save.should be_true
|
191
|
+
@doc.items.length.should == 4
|
192
|
+
@doc.gross_total.should == 130.0
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'should create items from array with prefixed hashes' do
|
196
|
+
# setting type eg: :type=>'LineItem' is optional
|
197
|
+
@doc.items = [
|
198
|
+
{ :line_item => { :position=>1, :name => 'Pork Chops', :quantity => 12, :price_single =>'10.00', :type=>'LineItem' }},
|
199
|
+
{ :sub_total_item => { :position=>2, :name => 'Pork Sub Total' }},
|
200
|
+
{ :divider_item => { :position=>2, :name => 'Yummi Beef', :type=>'DividerItem' }},
|
201
|
+
{ :line_item => { :position=>3, :name => 'Beef Jerky', :description=> 'Jaw Breaker',:quantity => 1, :price_single =>'10.00' }}
|
202
|
+
]
|
203
|
+
@doc.save.should be_true
|
204
|
+
@doc.items.length.should == 4
|
205
|
+
@doc.gross_total.should == 130.0
|
206
|
+
end
|
166
207
|
end
|
167
208
|
|
209
|
+
describe 'with items and line_items' do
|
210
|
+
before :all do
|
211
|
+
@contact = Contact.new(:type=>'Client', :organisation=>'Credit Note API-Tester')
|
212
|
+
@contact.save.should be_true
|
213
|
+
@doc = Invoice.new(:contact_id => @contact.id)
|
214
|
+
end
|
215
|
+
|
216
|
+
after :all do
|
217
|
+
delete_test_data(@doc, @contact)
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'should prefer line_items over items when both are present' do
|
221
|
+
@doc.items = [LineItem.new( :position=>12, :name => 'dropped', :quantity => 1, :price_single =>1, :type=>'LineItem' )]
|
222
|
+
@doc.line_items = [LineItem.new( :position=>12, :name => 'added', :quantity => 1, :price_single =>10, :type=>'LineItem' )]
|
223
|
+
@doc.save.should be_true
|
224
|
+
@doc.items.length.should == 1
|
225
|
+
@doc.gross_total.should == 10.0
|
226
|
+
end
|
227
|
+
|
228
|
+
it 'should manually remove line_items so items are used on update' do
|
229
|
+
# first save so AR loads both(items/line_items) from response
|
230
|
+
@doc.items = [ { :position=>1, :name => 'Pork Chops', :quantity => 1, :price_single =>'10.00', :type=>'LineItem' }]
|
231
|
+
@doc.save.should be_true
|
232
|
+
@doc.gross_total.should == 10.0
|
233
|
+
# edit
|
234
|
+
@doc.items << LineItem.new( :position=>2, :name => 'Puppy Seeds', :quantity => 1, :price_single =>1, :type=>'LineItem' )
|
235
|
+
@doc.line_items = nil # <= IMPORTANT part
|
236
|
+
|
237
|
+
@doc.save.should be_true
|
238
|
+
@doc.items.length.should == 2
|
239
|
+
@doc.gross_total.should == 11.0
|
240
|
+
end
|
241
|
+
|
242
|
+
end
|
168
243
|
end
|
244
|
+
|
169
245
|
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'resources_spec_helper'
|
2
|
+
|
3
|
+
unless sk_available?
|
4
|
+
puts "Sorry cannot connect to your SalesKing server, skipping real connections tests. Please check connection settings in spec_helper"
|
5
|
+
else
|
6
|
+
|
7
|
+
describe Payment do
|
8
|
+
|
9
|
+
before :all do
|
10
|
+
@contact = Contact.new(:type=>'Client', :organisation=>'Payment API-Tester')
|
11
|
+
@contact.save.should be_true
|
12
|
+
@doc = Invoice.new
|
13
|
+
@doc.title = 'A Document from the API for payment testing'
|
14
|
+
@doc.contact_id = @contact.id
|
15
|
+
@doc.save.should be_true
|
16
|
+
end
|
17
|
+
|
18
|
+
after :all do
|
19
|
+
payments = Payment.instantiate_collection(@doc.get(:payments))
|
20
|
+
payments.each { |p| p.destroy }
|
21
|
+
@doc.status = 'draft'
|
22
|
+
@doc.save
|
23
|
+
@contact.destroy
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "POST request for invoice" do
|
27
|
+
it "should create" do
|
28
|
+
p = Payment.new :amount => 10
|
29
|
+
|
30
|
+
# damn i hate active_resource
|
31
|
+
@doc.post(:payments, {}, p.encode)
|
32
|
+
payments_json = @doc.get(:payments)
|
33
|
+
payments = Payment.instantiate_collection(payments_json)
|
34
|
+
|
35
|
+
payments.first.amount.should == 10
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should create with method date external_ref" do
|
39
|
+
p = Payment.new :amount => 11,
|
40
|
+
:payment_method => "bank_transfer",
|
41
|
+
:date=> Date.today,
|
42
|
+
:external_ref => 'from sdk-test'
|
43
|
+
|
44
|
+
# damn i hate active_resource
|
45
|
+
@doc.post(:payments, {}, p.encode)
|
46
|
+
payments = Payment.instantiate_collection(@doc.get(:payments))
|
47
|
+
payment = payments.detect{|p| p.amount == 11 }
|
48
|
+
payment.external_ref.should == 'from sdk-test'
|
49
|
+
payment.date.should == Date.today.strftime("%Y-%m-%d")
|
50
|
+
# method is defined on Object .. TODO rename it in SK
|
51
|
+
payment.attributes['payment_method'].should == 'bank_transfer'
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should close related invoice" do
|
55
|
+
p = Payment.new :amount => 10
|
56
|
+
|
57
|
+
# damn i hate active_resource
|
58
|
+
@doc.post(:payments, {:new_doc_status=>'closed'}, p.encode)
|
59
|
+
doc = Invoice.find @doc.id
|
60
|
+
doc.status.should == 'closed'
|
61
|
+
doc.number.should be
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "direct POST create" do
|
67
|
+
it "should create" do
|
68
|
+
# relation MUST be set
|
69
|
+
p = Payment.new :amount => 12.34, :related_object_id=>@doc.id
|
70
|
+
p.save.should be_true
|
71
|
+
|
72
|
+
payments = Payment.instantiate_collection(@doc.get(:payments))
|
73
|
+
payments.map(&:amount).should include 12.34
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
def destroy_payment
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sk_sdk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -156,6 +156,7 @@ files:
|
|
156
156
|
- MIT-LICENSE
|
157
157
|
- README.rdoc
|
158
158
|
- Rakefile
|
159
|
+
- ci/Gemfile_ar2
|
159
160
|
- ci/Gemfile_ar2.lock
|
160
161
|
- lib/sk_sdk.rb
|
161
162
|
- lib/sk_sdk/README.rdoc
|
@@ -176,9 +177,10 @@ files:
|
|
176
177
|
- spec/sk_sdk/base_spec.rb
|
177
178
|
- spec/sk_sdk/oauth_spec.rb
|
178
179
|
- spec/sk_sdk/resources/README.rdoc
|
179
|
-
- spec/sk_sdk/resources/
|
180
|
+
- spec/sk_sdk/resources/contacts_spec.rb
|
180
181
|
- spec/sk_sdk/resources/credit_note_spec.rb
|
181
182
|
- spec/sk_sdk/resources/invoice_spec.rb
|
183
|
+
- spec/sk_sdk/resources/payment_spec.rb
|
182
184
|
- spec/sk_sdk/resources/product_spec.rb
|
183
185
|
- spec/sk_sdk/signed_request_spec.rb
|
184
186
|
- spec/sk_sdk/sync_field_spec.rb
|
@@ -198,7 +200,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
198
200
|
version: '0'
|
199
201
|
segments:
|
200
202
|
- 0
|
201
|
-
hash:
|
203
|
+
hash: 892546568127510729
|
202
204
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
203
205
|
none: false
|
204
206
|
requirements:
|
@@ -207,7 +209,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
207
209
|
version: '0'
|
208
210
|
segments:
|
209
211
|
- 0
|
210
|
-
hash:
|
212
|
+
hash: 892546568127510729
|
211
213
|
requirements: []
|
212
214
|
rubyforge_project:
|
213
215
|
rubygems_version: 1.8.24
|
@@ -1,98 +0,0 @@
|
|
1
|
-
require 'resources_spec_helper'
|
2
|
-
|
3
|
-
unless sk_available?
|
4
|
-
puts "Sorry cannot connect to your SalesKing server, skipping real connections tests. Please check connection settings in spec_helper"
|
5
|
-
else
|
6
|
-
|
7
|
-
describe Client, "with real connection" do
|
8
|
-
|
9
|
-
before :all do
|
10
|
-
@client = Client.new(:organisation=>'from testing API2')
|
11
|
-
@client.save
|
12
|
-
end
|
13
|
-
|
14
|
-
after :all do
|
15
|
-
#delete test client
|
16
|
-
@client.destroy
|
17
|
-
lambda {
|
18
|
-
client = Client.find(@client.id)
|
19
|
-
}.should raise_error(ActiveResource::ResourceNotFound)
|
20
|
-
end
|
21
|
-
|
22
|
-
it "should save" do
|
23
|
-
c = Client.new :organisation=>"Rack'n Roll"
|
24
|
-
c.save.should be_true
|
25
|
-
c.id.should_not be_empty
|
26
|
-
c.number.should_not be_empty
|
27
|
-
end
|
28
|
-
|
29
|
-
it "should fail create a client" do
|
30
|
-
client = Client.new(:organisation=>'from testing API2')
|
31
|
-
client.bank_iban = 'safasf'
|
32
|
-
client.save.should == false
|
33
|
-
client.errors.count.should == 1
|
34
|
-
client.errors.full_messages.should == ["Bank iban is invalid"]
|
35
|
-
end
|
36
|
-
|
37
|
-
it "should find a single client" do
|
38
|
-
client = Client.find(@client.id)
|
39
|
-
client.organisation.should == @client.organisation
|
40
|
-
end
|
41
|
-
|
42
|
-
it "should find clients" do
|
43
|
-
clients = Client.find(:all)
|
44
|
-
clients.should_not be_empty
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
|
49
|
-
describe Client, "with addresses" do
|
50
|
-
|
51
|
-
before :all do
|
52
|
-
#setup test client to work with
|
53
|
-
@client = Client.new(:organisation=>'Second from testing API2',
|
54
|
-
:addresses => [{ :zip => '50374', :city => 'Cologne' }] )
|
55
|
-
|
56
|
-
@client.save
|
57
|
-
end
|
58
|
-
|
59
|
-
after :all do
|
60
|
-
@client.destroy
|
61
|
-
lambda {
|
62
|
-
client = Client.find(@client.id)
|
63
|
-
}.should raise_error(ActiveResource::ResourceNotFound)
|
64
|
-
end
|
65
|
-
|
66
|
-
it "should create an address" do
|
67
|
-
@client.addresses.length.should == 1
|
68
|
-
@client.addresses.first.zip.should == '50374'
|
69
|
-
end
|
70
|
-
|
71
|
-
it "should edit an address" do
|
72
|
-
@client.addresses.length.should == 1
|
73
|
-
# puts @client.addresses.inspect
|
74
|
-
@client.addresses[0].zip = '40001'
|
75
|
-
@client.save
|
76
|
-
@client.addresses.length.should == 1
|
77
|
-
@client.addresses.first.zip.should == '40001'
|
78
|
-
end
|
79
|
-
|
80
|
-
it "should add an address" do
|
81
|
-
cnt_before = @client.addresses.length
|
82
|
-
adr = Address.new( { :zip => '37700', :city => 'Cologne' } )
|
83
|
-
@client.addresses << adr
|
84
|
-
@client.save
|
85
|
-
@client.addresses.length.should == cnt_before+1
|
86
|
-
end
|
87
|
-
|
88
|
-
it "should destroy an address" do
|
89
|
-
cnt_before = @client.addresses.length
|
90
|
-
@client.addresses.last._destroy = 1
|
91
|
-
@client.save
|
92
|
-
@client.reload
|
93
|
-
@client.addresses.length.should == cnt_before-1
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
|
98
|
-
end
|