sk_api_schema 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.
- data/.gitignore +4 -0
- data/README.rdoc +21 -0
- data/Rakefile +48 -0
- data/VERSION +1 -0
- data/json/v1.0/address.json +74 -0
- data/json/v1.0/client.json +169 -0
- data/json/v1.0/credit_note.json +122 -0
- data/json/v1.0/invoice.json +122 -0
- data/json/v1.0/line_item.json +73 -0
- data/lib/sk_api_schema.rb +1 -0
- data/lib/utils/serializer.rb +66 -0
- data/sk_api_schema.gemspec +60 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/utils/field_map_spec.rb +73 -0
- metadata +108 -0
data/.gitignore
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
= SalesKing Api Schema
|
2
|
+
|
3
|
+
SalesKing API description using JSON Schema(http://json-schema.org/)
|
4
|
+
|
5
|
+
For ruby users this project provides a gem with some basic utility functions
|
6
|
+
besides the schema. Other languages can take advantage of the raw json files.
|
7
|
+
|
8
|
+
To get a fully working ruby client take a look at http://github.com/salesking/sk-api
|
9
|
+
which will be replaced soon by a new gem at http://github.com/salesking/sk_api_activeresource
|
10
|
+
|
11
|
+
|
12
|
+
Notice: This gem is still evolving and will be used actively by salesking to deliver the api soon.
|
13
|
+
Atm the JSON files are the most interesting stuff in here.
|
14
|
+
|
15
|
+
== Install
|
16
|
+
|
17
|
+
gem install sk_api_schema
|
18
|
+
|
19
|
+
== Usage
|
20
|
+
|
21
|
+
Copyright (c) 2010 Georg Leciejewski, released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
require 'spec/rake/spectask'
|
5
|
+
|
6
|
+
begin
|
7
|
+
require 'jeweler'
|
8
|
+
Jeweler::Tasks.new do |gem|
|
9
|
+
gem.name = "sk_api_schema"
|
10
|
+
gem.summary = %Q{SalesKing API JSON Schema}
|
11
|
+
gem.description = %Q{SalesKing API JSON schema and utility methods}
|
12
|
+
gem.email = "gl@salesking.eu"
|
13
|
+
gem.homepage = "http://github.com/salesking/sk_api_schema"
|
14
|
+
gem.authors = ["Georg Leciejewski"]
|
15
|
+
gem.add_dependency 'activesupport'
|
16
|
+
gem.add_development_dependency "rspec"
|
17
|
+
end
|
18
|
+
Jeweler::GemcutterTasks.new
|
19
|
+
rescue LoadError
|
20
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
21
|
+
end
|
22
|
+
|
23
|
+
desc 'Default: run specs.'
|
24
|
+
task :default => :spec
|
25
|
+
|
26
|
+
spec_files = Rake::FileList["spec/**/*_spec.rb"]
|
27
|
+
|
28
|
+
desc "Run specs"
|
29
|
+
Spec::Rake::SpecTask.new do |t|
|
30
|
+
t.spec_files = spec_files
|
31
|
+
t.spec_opts = ["-c"]
|
32
|
+
end
|
33
|
+
|
34
|
+
desc "Generate code coverage"
|
35
|
+
Spec::Rake::SpecTask.new(:coverage) do |t|
|
36
|
+
t.spec_files = spec_files
|
37
|
+
t.rcov = true
|
38
|
+
t.rcov_opts = ['--exclude', 'spec,/var/lib/gems']
|
39
|
+
end
|
40
|
+
|
41
|
+
desc 'Generate sk_api_activeresource documentation.'
|
42
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
43
|
+
rdoc.rdoc_dir = 'rdoc'
|
44
|
+
rdoc.title = 'SalesKing-Api JSON Schema'
|
45
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
46
|
+
rdoc.rdoc_files.include('README')
|
47
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
48
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
@@ -0,0 +1,74 @@
|
|
1
|
+
{"type":"object",
|
2
|
+
"title": "address",
|
3
|
+
"description":"An address",
|
4
|
+
"properties": {
|
5
|
+
"id": {
|
6
|
+
"description": "uuid of the adress.",
|
7
|
+
"identity":true,
|
8
|
+
"readonly":true,
|
9
|
+
"type":"string"
|
10
|
+
},
|
11
|
+
"city": {
|
12
|
+
"description": "City for the address. Must at least be present for an address.",
|
13
|
+
"type":"string"
|
14
|
+
},
|
15
|
+
"address1": {
|
16
|
+
"description": "Should contain the street or otherwise primary address information.",
|
17
|
+
"optional":true,
|
18
|
+
"type":"string"
|
19
|
+
},
|
20
|
+
"address2": {
|
21
|
+
"description": "Additional address information, like floor number",
|
22
|
+
"optional":true,
|
23
|
+
"type":"string"
|
24
|
+
},
|
25
|
+
"pobox": {
|
26
|
+
"description": "Post office box number",
|
27
|
+
"optional":true,
|
28
|
+
"type":"string"
|
29
|
+
},
|
30
|
+
"zip": {
|
31
|
+
"description": "Zip number of the city. Length must be between 4..10",
|
32
|
+
"optional":true,
|
33
|
+
"type":"string"
|
34
|
+
},
|
35
|
+
"state": {
|
36
|
+
"description": "Country state of address",
|
37
|
+
"optional":true,
|
38
|
+
"type":"string"
|
39
|
+
},
|
40
|
+
"country": {
|
41
|
+
"description": "Country of the address.",
|
42
|
+
"optional":true,
|
43
|
+
"type":"string"
|
44
|
+
},
|
45
|
+
"created_at": {
|
46
|
+
"description": "Date the object was created in SK. Never changes aftwerwards",
|
47
|
+
"format":"date-time",
|
48
|
+
"readonly":true, "type":"string"
|
49
|
+
},
|
50
|
+
"updated_at": {
|
51
|
+
"description": "Date the object was edited in SK.",
|
52
|
+
"format":"date-time",
|
53
|
+
"readonly":true,
|
54
|
+
"type":"string"
|
55
|
+
},
|
56
|
+
"address_type": {
|
57
|
+
"description": "Type of the address, as seen by vCard definition.",
|
58
|
+
"enum":["work","home"],
|
59
|
+
"optional":true,
|
60
|
+
"type":"string"
|
61
|
+
},
|
62
|
+
"lat": {
|
63
|
+
"description": "Geolocation latitude",
|
64
|
+
"optional":true,
|
65
|
+
"type":"string"
|
66
|
+
},
|
67
|
+
"long": {
|
68
|
+
"description": "Geolocation longitude",
|
69
|
+
"optional":true,
|
70
|
+
"type":"string"
|
71
|
+
},
|
72
|
+
|
73
|
+
}
|
74
|
+
}
|
@@ -0,0 +1,169 @@
|
|
1
|
+
{"type":"object",
|
2
|
+
"title": "client",
|
3
|
+
"description": "A client as seen by SalesKing",
|
4
|
+
"properties": {
|
5
|
+
"id": {
|
6
|
+
"identity":true,
|
7
|
+
"optional":true,
|
8
|
+
"readonly":true,
|
9
|
+
"type":"string"
|
10
|
+
},
|
11
|
+
"number": {
|
12
|
+
"description": "Unique number, assigned from SK numbering scheme.",
|
13
|
+
"optional":true,
|
14
|
+
"type":"string"
|
15
|
+
},
|
16
|
+
"organisation": {
|
17
|
+
"description": "Name of a company. At least this or the lastname field must be filled for new records",
|
18
|
+
"type":"string"
|
19
|
+
},
|
20
|
+
"last_name": {
|
21
|
+
"description": "Last name of a person. At least this or the organisation field must be filled for new records",
|
22
|
+
"optional":true,
|
23
|
+
"type":"string"
|
24
|
+
},
|
25
|
+
"first_name": {
|
26
|
+
"description": "First name of a person.",
|
27
|
+
"optional":true,
|
28
|
+
"type":"string"
|
29
|
+
},
|
30
|
+
"gender": {
|
31
|
+
"description": "Can be empty for a company. Is used in salutation",
|
32
|
+
"optional":true,
|
33
|
+
"enum":["male", "female"],
|
34
|
+
"type":"string"
|
35
|
+
},
|
36
|
+
"position": {
|
37
|
+
"description": "Position of a person in a company.",
|
38
|
+
"optional":true,
|
39
|
+
"type":"string"
|
40
|
+
},
|
41
|
+
"title": {
|
42
|
+
"description": "Academical title of a person e.g. Dr., Prof",
|
43
|
+
"optional":true,
|
44
|
+
"type":"string"
|
45
|
+
},
|
46
|
+
"tax_number": {
|
47
|
+
"description": "Tax number, normaly applies to a private person",
|
48
|
+
"optional":true,
|
49
|
+
"type":"string"
|
50
|
+
},
|
51
|
+
"vat_number": {
|
52
|
+
"description": "VAT number, for a company or person paying value added taxes.",
|
53
|
+
"optional":true,
|
54
|
+
"type":"string"
|
55
|
+
},
|
56
|
+
"email": {
|
57
|
+
"description": "Email address of the contact.",
|
58
|
+
"optional":true,
|
59
|
+
"type":"string"
|
60
|
+
},
|
61
|
+
"url": {
|
62
|
+
"description": "An url associated with the person, e.g its company website.",
|
63
|
+
"optional":true,
|
64
|
+
"type":"string"
|
65
|
+
},
|
66
|
+
"birthday": {
|
67
|
+
"format":"date",
|
68
|
+
"optional":true,
|
69
|
+
"type":"string"
|
70
|
+
},
|
71
|
+
"tag_list": {
|
72
|
+
"description": "Space seperated list of tags.",
|
73
|
+
"optional":true,
|
74
|
+
"type":"string"
|
75
|
+
},
|
76
|
+
"created_at": {
|
77
|
+
"description": "Date the record was created in SK. Never changes afterwards.",
|
78
|
+
"format":"date-time",
|
79
|
+
"optional":true,
|
80
|
+
"readonly":true,
|
81
|
+
"type":"string"
|
82
|
+
},
|
83
|
+
"updated_at": {
|
84
|
+
"description": "Last date when the record was edited.",
|
85
|
+
"format":"date-time",
|
86
|
+
"optional":true,
|
87
|
+
"readonly":true,
|
88
|
+
"type":"string"
|
89
|
+
},
|
90
|
+
"bank_number": {
|
91
|
+
"description": "Number of the bank",
|
92
|
+
"optional":true,
|
93
|
+
"type":"string"
|
94
|
+
},
|
95
|
+
"bank_name": {
|
96
|
+
"description": "Name of the bank.",
|
97
|
+
"optional":true,
|
98
|
+
"type":"string"
|
99
|
+
},
|
100
|
+
"bank_account_number": {
|
101
|
+
"description": "Number of the bank account.",
|
102
|
+
"optional":true,
|
103
|
+
"type":"string"
|
104
|
+
},
|
105
|
+
"bank_iban": {
|
106
|
+
"description": "IBAN Number of the bank account. Is validated",
|
107
|
+
"optional":true,
|
108
|
+
"type":"string"
|
109
|
+
},
|
110
|
+
"bank_swift": {
|
111
|
+
"description": "SWIFT BIC- Bank Identifier Code",
|
112
|
+
"optional":true,
|
113
|
+
"type":"string"
|
114
|
+
},
|
115
|
+
"bank_owner": {
|
116
|
+
"description": "Owner of the bank account.",
|
117
|
+
"optional":true,
|
118
|
+
"type":"string"
|
119
|
+
},
|
120
|
+
"phone_fax": {
|
121
|
+
"description": "Fax number",
|
122
|
+
"optional":true,
|
123
|
+
"type":"string"
|
124
|
+
},
|
125
|
+
"phone_office": {
|
126
|
+
"description": "Office phone number",
|
127
|
+
"optional":true,
|
128
|
+
"type":"string"
|
129
|
+
},
|
130
|
+
"phone_home": {
|
131
|
+
"description": "Private phone number.",
|
132
|
+
"optional":true,
|
133
|
+
"type":"string"
|
134
|
+
},
|
135
|
+
"phone_mobile": {
|
136
|
+
"description": "Mobile phone number",
|
137
|
+
"optional":true,
|
138
|
+
"type":"string"
|
139
|
+
},
|
140
|
+
"lock_version": {
|
141
|
+
"description": "Increased on every edit, so SK can detect/prevent a concurrent edit by another user. First save wins.",
|
142
|
+
"optional":true,
|
143
|
+
"readonly":true,
|
144
|
+
"type":"integer"
|
145
|
+
},
|
146
|
+
"cash_discount": {
|
147
|
+
"description": "Default cash discount for new invoices.",
|
148
|
+
"optional":true,
|
149
|
+
"type":"number"
|
150
|
+
},
|
151
|
+
"due_days": {
|
152
|
+
"description": "Default due days for new invoices.",
|
153
|
+
"optional":true,
|
154
|
+
"type":"integer"
|
155
|
+
},
|
156
|
+
"address_field": {
|
157
|
+
"description": "Returns the address field used on new docs. Consist of Organisation name and default(first) address",
|
158
|
+
"optional":true,
|
159
|
+
"readonly":true,
|
160
|
+
"type":"string"
|
161
|
+
},
|
162
|
+
"addresses": {
|
163
|
+
"description": "A client can have many addresses, sorted by date descending(new first). Default address is the most recent one.",
|
164
|
+
"optional":true,
|
165
|
+
"type":"array",
|
166
|
+
"properties" : {"$ref":"./addresses.json#properties"}
|
167
|
+
}
|
168
|
+
}
|
169
|
+
}
|
@@ -0,0 +1,122 @@
|
|
1
|
+
{ "type":"object",
|
2
|
+
"title": "credit note",
|
3
|
+
"description": "A credit note",
|
4
|
+
"properties":{
|
5
|
+
"id":{
|
6
|
+
"description": "UUID assigned by SK",
|
7
|
+
"identity":true,
|
8
|
+
"optional":true,
|
9
|
+
"readonly":true,
|
10
|
+
"type":"string"
|
11
|
+
},
|
12
|
+
"number":{
|
13
|
+
"description": "Unique number assigned by SK credit note number schema. Auto-assigned when document is opened. Required unless doc status is draft.",
|
14
|
+
"optional":true,
|
15
|
+
"type":"string"
|
16
|
+
},
|
17
|
+
"address_field":{
|
18
|
+
"description": "Address field with the receiver. Shown in envelope window.",
|
19
|
+
"optional":true,
|
20
|
+
"type":"string"
|
21
|
+
},
|
22
|
+
"date":{
|
23
|
+
"description": "Date the credit note is issued. Automatically set when document is opened. Required unless doc status is draft.",
|
24
|
+
"format":"date",
|
25
|
+
"optional":true,
|
26
|
+
"type":"string"
|
27
|
+
},
|
28
|
+
"due_days":{
|
29
|
+
"description": "Used to calculate the due date of the credit note. Useless if date and due date are present.",
|
30
|
+
"optional":true,
|
31
|
+
"type":"integer"
|
32
|
+
},
|
33
|
+
"due_date":{
|
34
|
+
"description": "Auto-calculated from date + due days if empty and the document is opened.",
|
35
|
+
"format":"date",
|
36
|
+
"optional":true,
|
37
|
+
"type":"string"
|
38
|
+
},
|
39
|
+
"status":{
|
40
|
+
"description": "A new document is always a draft unless otherwise stated. Only draft documents can be deleted. When a doc is opened it's number, date and due date are auto-set",
|
41
|
+
"optional":true,
|
42
|
+
"default":"draft",
|
43
|
+
"enum":["draft","open","closed"],
|
44
|
+
"type":"string"
|
45
|
+
},
|
46
|
+
"payment_method":{
|
47
|
+
"description": "How the document is beeing payed. Used in new payments.",
|
48
|
+
"optional":true,
|
49
|
+
"enum":["cash","bank_transfer","credit_card","paypal","direct_debit","cheque"],
|
50
|
+
"type":"string"
|
51
|
+
},
|
52
|
+
"title":{
|
53
|
+
"description": "The headline of a document. Use SK placeholders to prevent exessive typing e.g. 'Your credit note [number]'",
|
54
|
+
"optional":true,
|
55
|
+
"type":"string"
|
56
|
+
},
|
57
|
+
"notes_before":{
|
58
|
+
"description": "Notes shown before the line items. Normaly contains salutation and other introductional information. SK placeholders can be used.",
|
59
|
+
"optional":true,
|
60
|
+
"type":"string"
|
61
|
+
},
|
62
|
+
"notes_after":{
|
63
|
+
"description": "Notes shown after the line items. Can contain information about payments, bank account or a thank-you message. SK placeholders can be used.",
|
64
|
+
"optional":true,
|
65
|
+
"type":"string"
|
66
|
+
},
|
67
|
+
"tag_list": {
|
68
|
+
"description": "Space seperated list of tags.",
|
69
|
+
"optional":true,
|
70
|
+
"type":"string"
|
71
|
+
},
|
72
|
+
"client":{
|
73
|
+
"description": "The client for the document. New documents cannot create a client, use client_id field to set it.",
|
74
|
+
"optional":true,
|
75
|
+
"readonly":true,
|
76
|
+
"type":"object",
|
77
|
+
"properties":{"$ref":"./client.json#properties"}
|
78
|
+
},
|
79
|
+
"client_id":{
|
80
|
+
"description": "The clients uuid, must be set for a new document. New documents take the clients address field, due days and cash discount if those fields are not set.",
|
81
|
+
"type":"string"
|
82
|
+
},
|
83
|
+
"line_items":{
|
84
|
+
"description": "Line items for the document",
|
85
|
+
"optional":true,
|
86
|
+
"type":"array",
|
87
|
+
"properties":{"$ref":"./address.json#properties"}
|
88
|
+
},
|
89
|
+
"created_at":{
|
90
|
+
"description": "Date the object was created in SK. Never changes aftwerwards.",
|
91
|
+
"format":"date-time",
|
92
|
+
"optional":true,
|
93
|
+
"readonly":true,
|
94
|
+
"type":"string"
|
95
|
+
},
|
96
|
+
"updated_at":{
|
97
|
+
"description": "Date the object was edited in SK.",
|
98
|
+
"format":"date-time",
|
99
|
+
"optional":true,
|
100
|
+
"readonly":true,
|
101
|
+
"type":"string"
|
102
|
+
},
|
103
|
+
"lock_version":{
|
104
|
+
"description": "Auto-incremented by SK to prevent concurrent updateing. First save wins.",
|
105
|
+
"optional":true,
|
106
|
+
"readonly":true,
|
107
|
+
"type":"integer"
|
108
|
+
},
|
109
|
+
"price_total":{
|
110
|
+
"description": "Net total sum of all line items, 6 decimals places",
|
111
|
+
"optional":true,
|
112
|
+
"readonly":true,
|
113
|
+
"type":"number"
|
114
|
+
},
|
115
|
+
"price_tax":{
|
116
|
+
"description": "Summed up tax total of all line items, 2 decimals places",
|
117
|
+
"optional":true,
|
118
|
+
"readonly":true,
|
119
|
+
"type":"number"
|
120
|
+
}
|
121
|
+
}
|
122
|
+
}
|
@@ -0,0 +1,122 @@
|
|
1
|
+
{ "type":"object",
|
2
|
+
"title": "invoice",
|
3
|
+
"description": "An invoice",
|
4
|
+
"properties":{
|
5
|
+
"id":{
|
6
|
+
"description": "UUID assigned by SK",
|
7
|
+
"identity":true,
|
8
|
+
"optional":true,
|
9
|
+
"readonly":true,
|
10
|
+
"type":"string"
|
11
|
+
},
|
12
|
+
"number":{
|
13
|
+
"description": "Unique number assigned by SK invoice number schema. Auto-assigned when invoice is opened. Required unless doc status is draft.",
|
14
|
+
"optional":true,
|
15
|
+
"type":"string"
|
16
|
+
},
|
17
|
+
"address_field":{
|
18
|
+
"description": "Address field with the receiver. Shown in envelope window.",
|
19
|
+
"optional":true,
|
20
|
+
"type":"string"
|
21
|
+
},
|
22
|
+
"date":{
|
23
|
+
"description": "Date the invoice is issued. Automatically set when invoice is opened. Required unless doc status is draft.",
|
24
|
+
"format":"date",
|
25
|
+
"optional":true,
|
26
|
+
"type":"string"
|
27
|
+
},
|
28
|
+
"due_days":{
|
29
|
+
"description": "Used to calculate the due date of the invoice. Useless if date and due date are present.",
|
30
|
+
"optional":true,
|
31
|
+
"type":"integer"
|
32
|
+
},
|
33
|
+
"due_date":{
|
34
|
+
"description": "Auto-calculated from date + due days if empty and the invoice is opened.",
|
35
|
+
"format":"date",
|
36
|
+
"optional":true,
|
37
|
+
"type":"string"
|
38
|
+
},
|
39
|
+
"status":{
|
40
|
+
"description": "A new document is always a draft unless otherwise stated. Only draft invoices can be deleted. When a doc is opened it's number, date and due date are auto-set",
|
41
|
+
"optional":true,
|
42
|
+
"default":"draft",
|
43
|
+
"enum":["draft","open","closed"],
|
44
|
+
"type":"string"
|
45
|
+
},
|
46
|
+
"payment_method":{
|
47
|
+
"description": "How the invoce is beeing payed. Used in new payments.",
|
48
|
+
"optional":true,
|
49
|
+
"enum":["cash","bank_transfer","credit_card","paypal","direct_debit","cheque"],
|
50
|
+
"type":"string"
|
51
|
+
},
|
52
|
+
"title":{
|
53
|
+
"description": "The headline of a document. Use SK placeholders to prevent exessive typing e.g. 'Your invoice [number]'",
|
54
|
+
"optional":true,
|
55
|
+
"type":"string"
|
56
|
+
},
|
57
|
+
"notes_before":{
|
58
|
+
"description": "Notes shown before the line items. Normaly contains salutation and other introductional information. SK placeholders can be used.",
|
59
|
+
"optional":true,
|
60
|
+
"type":"string"
|
61
|
+
},
|
62
|
+
"notes_after":{
|
63
|
+
"description": "Notes shown after the line items. Can contain information about payments, bank account or a thank-you message. SK placeholders can be used.",
|
64
|
+
"optional":true,
|
65
|
+
"type":"string"
|
66
|
+
},
|
67
|
+
"tag_list": {
|
68
|
+
"description": "Space seperated list of tags.",
|
69
|
+
"optional":true,
|
70
|
+
"type":"string"
|
71
|
+
},
|
72
|
+
"client":{
|
73
|
+
"description": "The client for the document. New documents cannot create a client, use client_id field to set it.",
|
74
|
+
"optional":true,
|
75
|
+
"readonly":true,
|
76
|
+
"type":"object",
|
77
|
+
"properties":{"$ref":"./client.json#properties"}
|
78
|
+
},
|
79
|
+
"client_id":{
|
80
|
+
"description": "The clients uuid, must be set for a new document. New invoices take the clients address field, due days and cash discount if those fields are not set.",
|
81
|
+
"type":"string"
|
82
|
+
},
|
83
|
+
"line_items":{
|
84
|
+
"description": "Line items for the document",
|
85
|
+
"optional":true,
|
86
|
+
"type":"array",
|
87
|
+
"properties":{"$ref":"./address.json#properties"}
|
88
|
+
},
|
89
|
+
"created_at":{
|
90
|
+
"description": "Date the object was created in SK. Never changes aftwerwards.",
|
91
|
+
"format":"date-time",
|
92
|
+
"optional":true,
|
93
|
+
"readonly":true,
|
94
|
+
"type":"string"
|
95
|
+
},
|
96
|
+
"updated_at":{
|
97
|
+
"description": "Date the object was edited in SK.",
|
98
|
+
"format":"date-time",
|
99
|
+
"optional":true,
|
100
|
+
"readonly":true,
|
101
|
+
"type":"string"
|
102
|
+
},
|
103
|
+
"lock_version":{
|
104
|
+
"description": "Auto-incremented by SK to prevent concurrent updateing. First save wins.",
|
105
|
+
"optional":true,
|
106
|
+
"readonly":true,
|
107
|
+
"type":"integer"
|
108
|
+
},
|
109
|
+
"price_total":{
|
110
|
+
"description": "Net total sum of all line items, 6 decimals places",
|
111
|
+
"optional":true,
|
112
|
+
"readonly":true,
|
113
|
+
"type":"number"
|
114
|
+
},
|
115
|
+
"price_tax":{
|
116
|
+
"description": "Summed up tax total of all line items, 2 decimals places",
|
117
|
+
"optional":true,
|
118
|
+
"readonly":true,
|
119
|
+
"type":"number"
|
120
|
+
}
|
121
|
+
}
|
122
|
+
}
|
@@ -0,0 +1,73 @@
|
|
1
|
+
{ "type":"object",
|
2
|
+
"title": "line item",
|
3
|
+
"description": "A line item for a document",
|
4
|
+
"properties":{
|
5
|
+
"id":{
|
6
|
+
"description": "uuid of the item.",
|
7
|
+
"identity":true,
|
8
|
+
"readonly":true,
|
9
|
+
"type":"string"
|
10
|
+
},
|
11
|
+
"position":{
|
12
|
+
"description": "Required since items are sorted by position.",
|
13
|
+
"type":"integer"
|
14
|
+
},
|
15
|
+
"name":{
|
16
|
+
"description": "The name of an item",
|
17
|
+
"optional":true,
|
18
|
+
"type":"string"
|
19
|
+
},
|
20
|
+
"description":{
|
21
|
+
"description": "Item description",
|
22
|
+
"optional":true,
|
23
|
+
"type":"string"
|
24
|
+
},
|
25
|
+
"price_single":{
|
26
|
+
"description": "Net price of a single item",
|
27
|
+
"type":"number"
|
28
|
+
},
|
29
|
+
"tax":{
|
30
|
+
"description": "Tax percent for a single item.",
|
31
|
+
"optional":true,
|
32
|
+
"type":"number"
|
33
|
+
},
|
34
|
+
"discount":{
|
35
|
+
"description": "Discount in percent applied to the items net total",
|
36
|
+
"optional":true,
|
37
|
+
"type":"number"
|
38
|
+
},
|
39
|
+
"quantity_unit":{
|
40
|
+
"description": "Unit like kg, days, month.",
|
41
|
+
"optional":true,
|
42
|
+
"type":"string"
|
43
|
+
},
|
44
|
+
"quantity":{
|
45
|
+
"description": "Quantity of the item.",
|
46
|
+
"type":"number"
|
47
|
+
},
|
48
|
+
"product_id":{
|
49
|
+
"description": "An item can reference a product by its uuid. See use_product",
|
50
|
+
"optional":true,
|
51
|
+
"type":"string"
|
52
|
+
},
|
53
|
+
"use_product":{
|
54
|
+
"description": "If set and product_id is present, the products name, description, quantity, unit, price are copied if the according item fields are missing.",
|
55
|
+
"optional":true,
|
56
|
+
"type":"integer"
|
57
|
+
},
|
58
|
+
"created_at":{
|
59
|
+
"description": "Date the object was created in SK. Never changes aftwerwards",
|
60
|
+
"format":"date-time",
|
61
|
+
"optional":true,
|
62
|
+
"readonly":true,
|
63
|
+
"type":"string"
|
64
|
+
},
|
65
|
+
"updated_at":{
|
66
|
+
"description": "Date the object was edited in SK.",
|
67
|
+
"format":"date-time",
|
68
|
+
"optional":true,
|
69
|
+
"readonly":true,
|
70
|
+
"type":"string"
|
71
|
+
}
|
72
|
+
}
|
73
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'activesupport'
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module SKApi
|
2
|
+
module Utils
|
3
|
+
# Mixed into Resources::Base providing to_hash and to_json serialisation for
|
4
|
+
# SKApi Resources.
|
5
|
+
# Inside SalesKing this serialising is used to render the output.
|
6
|
+
# f.ex. in the clients api controller
|
7
|
+
# => SKApi::Resources::Client.to_json(a_client)
|
8
|
+
# This way you can keep your API client up to date by using the resources and
|
9
|
+
# relying on SKApi::Resources::Client.schema
|
10
|
+
module Serializer
|
11
|
+
def self.included(base)
|
12
|
+
base.extend ClassMethods
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
|
17
|
+
def schema_to_hash
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
# Create a Hash with the available (api)object attributes defined in api_fields.
|
22
|
+
#
|
23
|
+
# ==== Parameter
|
24
|
+
# obj<object>:. An ruby object which is returned as hash
|
25
|
+
def to_hash_from_schema(obj)
|
26
|
+
# first set the root node to the objects class name as symbol
|
27
|
+
obj_class_name = obj.class.name.split('::').last.underscore
|
28
|
+
# obj_class_name = obj.class.to_s.underscore.to_sym
|
29
|
+
data = { obj_class_name => {} }
|
30
|
+
# iterate over the defined api fields hash
|
31
|
+
self.schema_props.each do |field, props|
|
32
|
+
if props['type'] == 'array'
|
33
|
+
# always set the field, so the user can expect an empty array
|
34
|
+
data[obj_class_name][field] = []
|
35
|
+
if rel_objects = obj.send( field )
|
36
|
+
rel_objects.each do |rel_obj|
|
37
|
+
# setup scope for related class
|
38
|
+
klass = "SKApi::Resources::#{rel_obj.class}".constantize
|
39
|
+
# call related objects to_hash_from_schema method ex: data[:client][:addresses] << SKApi::Models::Address.to_hash_from_schema(object)
|
40
|
+
data[obj_class_name][field] << klass.to_hash_from_schema(rel_obj)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
elsif props['type'] == 'object' # a singular resource TODO should we add an empty object?
|
44
|
+
if rel_obj = obj.send( field )
|
45
|
+
klass = "SKApi::Resources::#{rel_obj.class}".constantize
|
46
|
+
# ex: data['invoice']['client'] = SKApi::Models::Client.to_hash_from_schema(client)
|
47
|
+
data[obj_class_name][field] = klass.to_hash_from_schema(rel_obj)
|
48
|
+
end
|
49
|
+
else # a simple field which can be directly called, only added of objects know its
|
50
|
+
data[obj_class_name][field] = obj.send(field) if obj.respond_to?(field.to_sym)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
data
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_json(obj)
|
57
|
+
data = self.to_hash_from_schema(obj)
|
58
|
+
# data[:links] = self.api_links
|
59
|
+
ActiveSupport::JSON.encode(data)
|
60
|
+
end
|
61
|
+
|
62
|
+
end #ClassMethods
|
63
|
+
|
64
|
+
end #mixin
|
65
|
+
end #utils
|
66
|
+
end #SKApi
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{sk_api_schema}
|
8
|
+
s.version = "0.0.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Georg Leciejewski"]
|
12
|
+
s.date = %q{2010-11-08}
|
13
|
+
s.description = %q{SalesKing API JSON schema and utility methods}
|
14
|
+
s.email = %q{gl@salesking.eu}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.rdoc"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".gitignore",
|
20
|
+
"README.rdoc",
|
21
|
+
"Rakefile",
|
22
|
+
"VERSION",
|
23
|
+
"json/v1.0/address.json",
|
24
|
+
"json/v1.0/client.json",
|
25
|
+
"json/v1.0/credit_note.json",
|
26
|
+
"json/v1.0/invoice.json",
|
27
|
+
"json/v1.0/line_item.json",
|
28
|
+
"lib/sk_api_schema.rb",
|
29
|
+
"lib/utils/serializer.rb",
|
30
|
+
"sk_api_schema.gemspec",
|
31
|
+
"spec/spec_helper.rb",
|
32
|
+
"spec/utils/field_map_spec.rb"
|
33
|
+
]
|
34
|
+
s.homepage = %q{http://github.com/salesking/sk_api_schema}
|
35
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
36
|
+
s.require_paths = ["lib"]
|
37
|
+
s.rubygems_version = %q{1.3.7}
|
38
|
+
s.summary = %q{SalesKing API JSON Schema}
|
39
|
+
s.test_files = [
|
40
|
+
"spec/spec_helper.rb",
|
41
|
+
"spec/utils/field_map_spec.rb"
|
42
|
+
]
|
43
|
+
|
44
|
+
if s.respond_to? :specification_version then
|
45
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
46
|
+
s.specification_version = 3
|
47
|
+
|
48
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
49
|
+
s.add_runtime_dependency(%q<activesupport>, [">= 0"])
|
50
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
51
|
+
else
|
52
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
53
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
54
|
+
end
|
55
|
+
else
|
56
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
57
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe SKApi::Utils::FieldMap do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
@loc_obj = LocalContact.new
|
7
|
+
@rem_obj = RemoteContact.new()
|
8
|
+
@map = SKApi::Utils::FieldMap.new(@loc_obj, @rem_obj, map_hash)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should create a mapping" do
|
12
|
+
@map.outdated?.should be_false # both objects are empty
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should find outdated fields" do
|
16
|
+
@loc_obj.firstname = 'theo'
|
17
|
+
@map.outdated?.should be_true
|
18
|
+
@map.outdated.first[:loc_key].should == :firstname
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should update outdated remote fields" do
|
22
|
+
@loc_obj.firstname = 'theo'
|
23
|
+
@map.update_remote_outdated
|
24
|
+
@rem_obj.first_name.should == @loc_obj.firstname
|
25
|
+
# test logging
|
26
|
+
@map.log.should_not be_empty
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should update outdated local fields" do
|
30
|
+
@rem_obj.first_name = 'Heinz'
|
31
|
+
@map.update_local_outdated
|
32
|
+
@rem_obj.first_name.should == @loc_obj.firstname
|
33
|
+
@map.log.length.should == 1
|
34
|
+
end
|
35
|
+
# it "should update outdated local fields" do
|
36
|
+
# @rem_obj.first_name = 'Heinz'
|
37
|
+
# @map.outdated?
|
38
|
+
# @map.update_local_outdated
|
39
|
+
# @rem_obj.first_name.should == @loc_obj.firstname
|
40
|
+
# end
|
41
|
+
|
42
|
+
def map_hash
|
43
|
+
[
|
44
|
+
{:loc_key => :firstname, :rem_key => :first_name},
|
45
|
+
{:loc_key => :street, :rem_key => :address1},
|
46
|
+
{:loc_key => :postcode, :rem_key => :zip},
|
47
|
+
{:loc_key => :city, :rem_key => :city},
|
48
|
+
{:loc_key => :gender, :rem_key => :gender, :trans => { :obj=>'TransferFunctions',
|
49
|
+
:loc_trans => 'set_local_gender',
|
50
|
+
:rem_trans => 'set_remote_gender'}
|
51
|
+
}
|
52
|
+
]
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
class RemoteContact
|
58
|
+
attr_accessor :first_name, :address1, :zip, :city, :gender
|
59
|
+
end
|
60
|
+
class LocalContact
|
61
|
+
attr_accessor :firstname, :street, :postcode, :city, :gender
|
62
|
+
end
|
63
|
+
|
64
|
+
class TransferFunctions
|
65
|
+
def self.set_local_gender(remote_val)
|
66
|
+
return 'male' if remote_val == 'm'
|
67
|
+
return 'female' if remote_val == 'f'
|
68
|
+
end
|
69
|
+
def self.set_remote_gender(local_val)
|
70
|
+
return 'm' if local_val == 'male'
|
71
|
+
return 'f' if local_val == 'female'
|
72
|
+
end
|
73
|
+
end
|
metadata
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sk_api_schema
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Georg Leciejewski
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-11-08 00:00:00 +01:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: activesupport
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: rspec
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id002
|
49
|
+
description: SalesKing API JSON schema and utility methods
|
50
|
+
email: gl@salesking.eu
|
51
|
+
executables: []
|
52
|
+
|
53
|
+
extensions: []
|
54
|
+
|
55
|
+
extra_rdoc_files:
|
56
|
+
- README.rdoc
|
57
|
+
files:
|
58
|
+
- .gitignore
|
59
|
+
- README.rdoc
|
60
|
+
- Rakefile
|
61
|
+
- VERSION
|
62
|
+
- json/v1.0/address.json
|
63
|
+
- json/v1.0/client.json
|
64
|
+
- json/v1.0/credit_note.json
|
65
|
+
- json/v1.0/invoice.json
|
66
|
+
- json/v1.0/line_item.json
|
67
|
+
- lib/sk_api_schema.rb
|
68
|
+
- lib/utils/serializer.rb
|
69
|
+
- sk_api_schema.gemspec
|
70
|
+
- spec/spec_helper.rb
|
71
|
+
- spec/utils/field_map_spec.rb
|
72
|
+
has_rdoc: true
|
73
|
+
homepage: http://github.com/salesking/sk_api_schema
|
74
|
+
licenses: []
|
75
|
+
|
76
|
+
post_install_message:
|
77
|
+
rdoc_options:
|
78
|
+
- --charset=UTF-8
|
79
|
+
require_paths:
|
80
|
+
- lib
|
81
|
+
required_ruby_version: !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
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
hash: 3
|
96
|
+
segments:
|
97
|
+
- 0
|
98
|
+
version: "0"
|
99
|
+
requirements: []
|
100
|
+
|
101
|
+
rubyforge_project:
|
102
|
+
rubygems_version: 1.3.7
|
103
|
+
signing_key:
|
104
|
+
specification_version: 3
|
105
|
+
summary: SalesKing API JSON Schema
|
106
|
+
test_files:
|
107
|
+
- spec/spec_helper.rb
|
108
|
+
- spec/utils/field_map_spec.rb
|