sk_api_schema 0.0.1 → 0.0.2
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/VERSION +1 -1
- data/json/v1.0/address.json +1 -2
- data/json/v1.0/attachment.json +59 -0
- data/json/v1.0/invoice.json +7 -0
- data/lib/sk_api_schema.rb +65 -1
- data/sk_api_schema.gemspec +6 -6
- data/spec/sk_api_schema_spec.rb +76 -0
- data/spec/spec_helper.rb +1 -1
- metadata +7 -7
- data/lib/utils/serializer.rb +0 -66
- data/spec/utils/field_map_spec.rb +0 -73
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.2
|
data/json/v1.0/address.json
CHANGED
@@ -0,0 +1,59 @@
|
|
1
|
+
{ "type":"object",
|
2
|
+
"title": "attachment",
|
3
|
+
"description":"An file attachment",
|
4
|
+
"properties": {
|
5
|
+
"id": {
|
6
|
+
"description": "uuid of the object.",
|
7
|
+
"identity":true,
|
8
|
+
"readonly":true,
|
9
|
+
"type":"string"
|
10
|
+
},
|
11
|
+
"filename": {
|
12
|
+
"description": "The filename as set when uploaded",
|
13
|
+
"optional":true,
|
14
|
+
"readonly":true,
|
15
|
+
"type":"string"
|
16
|
+
},
|
17
|
+
"disk_filename": {
|
18
|
+
"description": "The filename as set by SK",
|
19
|
+
"optional":true,
|
20
|
+
"readonly":true,
|
21
|
+
"type":"string"
|
22
|
+
},
|
23
|
+
"url": {
|
24
|
+
"description": "File download url. Unique and valid for 15 minutes, public accessible.",
|
25
|
+
"optional":true,
|
26
|
+
"readonly":true,
|
27
|
+
"type":"string"
|
28
|
+
},
|
29
|
+
"content_type": {
|
30
|
+
"description": "Auto detected on upload. Might not always reflect the real content type",
|
31
|
+
"optional":true,
|
32
|
+
"readonly":true,
|
33
|
+
"type":"string"
|
34
|
+
},
|
35
|
+
"size": {
|
36
|
+
"description": "Filesize in kb. Auto detected on upload.",
|
37
|
+
"optional":true,
|
38
|
+
"readonly":true,
|
39
|
+
"type":"integer"
|
40
|
+
},
|
41
|
+
"is_signed": {
|
42
|
+
"description": "True if the file(pdf) has been digitally signed.",
|
43
|
+
"optional":true,
|
44
|
+
"type":"boolean"
|
45
|
+
},
|
46
|
+
"created_at": {
|
47
|
+
"description": "Date the object was created in SK. Never changes aftwerwards",
|
48
|
+
"format":"date-time",
|
49
|
+
"readonly":true, "type":"string"
|
50
|
+
},
|
51
|
+
"updated_at": {
|
52
|
+
"description": "Date the object was edited in SK.",
|
53
|
+
"format":"date-time",
|
54
|
+
"readonly":true,
|
55
|
+
"type":"string"
|
56
|
+
}
|
57
|
+
|
58
|
+
}
|
59
|
+
}
|
data/json/v1.0/invoice.json
CHANGED
@@ -76,6 +76,13 @@
|
|
76
76
|
"type":"object",
|
77
77
|
"properties":{"$ref":"./client.json#properties"}
|
78
78
|
},
|
79
|
+
"archived_pdf":{
|
80
|
+
"description": "Archived PDF version of the document. Is created when an document is printed and archived. A document can have multiple archived versions. This only returns the most recent one. ",
|
81
|
+
"optional":true,
|
82
|
+
"readonly":true,
|
83
|
+
"type":"object",
|
84
|
+
"properties":{"$ref":"./attachment.json#properties"}
|
85
|
+
},
|
79
86
|
"client_id":{
|
80
87
|
"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
88
|
"type":"string"
|
data/lib/sk_api_schema.rb
CHANGED
@@ -1 +1,65 @@
|
|
1
|
-
require 'activesupport'
|
1
|
+
require 'activesupport'
|
2
|
+
|
3
|
+
module SK
|
4
|
+
module Api
|
5
|
+
class Schema
|
6
|
+
|
7
|
+
# Read a schema with a given version and return it as hash
|
8
|
+
# See ../json folder for available schema's and versions
|
9
|
+
# === Parameter
|
10
|
+
# schema<String|Symbol>::name of the schema, available ones are in json directory
|
11
|
+
# version<String>:: version to read, this is the folder name where the schema is in.
|
12
|
+
def self.read(schema, version)
|
13
|
+
file_path = File.join(File.dirname(__FILE__), '../json', version, "#{schema}.json")
|
14
|
+
plain_data = File.open(file_path, 'r'){|f| f.read}
|
15
|
+
ActiveSupport::JSON.decode(plain_data)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Create a Hash with the available (api)object attributes defined in
|
19
|
+
# schema properties.
|
20
|
+
#
|
21
|
+
# === Example
|
22
|
+
# obj = Invoice.new(:title =>'hello world', :number=>'4711')
|
23
|
+
# obj_hash = Sk::Api::Schema.to_hash_from_schema(obj, 'v1.0')
|
24
|
+
#
|
25
|
+
# obj_hash => { invoice =>{'title'=>'hello world', 'number'=>'4711' } }
|
26
|
+
#
|
27
|
+
# === Parameter
|
28
|
+
# obj<Object>:. An ruby object which is returned as hash
|
29
|
+
# version<String>:. An ruby object which is returned as hash
|
30
|
+
# === Return
|
31
|
+
# <Hash{String=>{String=>Mixed}}>:: The object as hash:
|
32
|
+
# { invoice =>{'title'=>'hello world', 'number'=>''4711 } }
|
33
|
+
def self.to_hash_from_schema(obj, version)
|
34
|
+
# get objects class name without inheritance
|
35
|
+
obj_class_name = obj.class.name.split('::').last.underscore
|
36
|
+
# init data hash
|
37
|
+
data = {}
|
38
|
+
# get schema
|
39
|
+
schema = self.read(obj_class_name, version)
|
40
|
+
# iterate over the defined schema fields
|
41
|
+
schema['properties'].each do |field, prop|
|
42
|
+
if prop['type'] == 'array'
|
43
|
+
# always set an empty array
|
44
|
+
data[field] = []
|
45
|
+
if rel_objects = obj.send( field )
|
46
|
+
rel_objects.each do |rel_obj|
|
47
|
+
# call related objects to_hash_from_schema method ex: data[:client][:addresses] << SKApi::Models::Address.to_hash_from_schema(object)
|
48
|
+
data[field] << self.to_hash_from_schema(rel_obj, version)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
elsif prop['type'] == 'object' # a singular related object
|
52
|
+
data[field] = nil
|
53
|
+
if rel_obj = obj.send( field )
|
54
|
+
data[field] = self.to_hash_from_schema(rel_obj, version)
|
55
|
+
end
|
56
|
+
else # a simple field is only added if objects know its
|
57
|
+
data[field] = obj.send(field) if obj.respond_to?(field.to_sym)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
{ obj_class_name => data }
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/sk_api_schema.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{sk_api_schema}
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Georg Leciejewski"]
|
12
|
-
s.date = %q{2010-11-
|
12
|
+
s.date = %q{2010-11-11}
|
13
13
|
s.description = %q{SalesKing API JSON schema and utility methods}
|
14
14
|
s.email = %q{gl@salesking.eu}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -21,15 +21,15 @@ Gem::Specification.new do |s|
|
|
21
21
|
"Rakefile",
|
22
22
|
"VERSION",
|
23
23
|
"json/v1.0/address.json",
|
24
|
+
"json/v1.0/attachment.json",
|
24
25
|
"json/v1.0/client.json",
|
25
26
|
"json/v1.0/credit_note.json",
|
26
27
|
"json/v1.0/invoice.json",
|
27
28
|
"json/v1.0/line_item.json",
|
28
29
|
"lib/sk_api_schema.rb",
|
29
|
-
"lib/utils/serializer.rb",
|
30
30
|
"sk_api_schema.gemspec",
|
31
|
-
"spec/
|
32
|
-
"spec/
|
31
|
+
"spec/sk_api_schema_spec.rb",
|
32
|
+
"spec/spec_helper.rb"
|
33
33
|
]
|
34
34
|
s.homepage = %q{http://github.com/salesking/sk_api_schema}
|
35
35
|
s.rdoc_options = ["--charset=UTF-8"]
|
@@ -38,7 +38,7 @@ Gem::Specification.new do |s|
|
|
38
38
|
s.summary = %q{SalesKing API JSON Schema}
|
39
39
|
s.test_files = [
|
40
40
|
"spec/spec_helper.rb",
|
41
|
-
"spec/
|
41
|
+
"spec/sk_api_schema_spec.rb"
|
42
42
|
]
|
43
43
|
|
44
44
|
if s.respond_to? :specification_version then
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe SK::Api::Schema do
|
4
|
+
|
5
|
+
it "should read json schema file" do
|
6
|
+
schema = SK::Api::Schema.read(:invoice, 'v1.0')
|
7
|
+
schema['title'].should == 'invoice'
|
8
|
+
schema['type'].should == 'object'
|
9
|
+
schema['properties'].should be_a Hash
|
10
|
+
schema['properties']['id']['identity'].should be_true
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should raise error if version folder does not exist" do
|
14
|
+
lambda{
|
15
|
+
SK::Api::Schema.read(:invoice, 'v3.0')
|
16
|
+
}.should raise_error
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should raise error if schema file does not exist" do
|
20
|
+
lambda{
|
21
|
+
SK::Api::Schema.read(:nope, 'v1.0')
|
22
|
+
}.should raise_error
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
describe SK::Api::Schema, 'object parsing' do
|
28
|
+
|
29
|
+
before :each do
|
30
|
+
@invoice = Invoice.new
|
31
|
+
@invoice.id = 'some-uuid'
|
32
|
+
@invoice.title = 'Your Invoice'
|
33
|
+
@invoice.number = '911'
|
34
|
+
|
35
|
+
@client = Client.new
|
36
|
+
@client.id = 'some-uuid'
|
37
|
+
@client.organisation = 'Dirty Food Inc.'
|
38
|
+
@client.number = '911'
|
39
|
+
|
40
|
+
@item = LineItem.new
|
41
|
+
@item.id = 'some-uuid'
|
42
|
+
@item.name = 'Pork Chops'
|
43
|
+
@item.description = 'Yummi Pork chopped by mexian emigrants'
|
44
|
+
@item.position = 1
|
45
|
+
@item.price_single = 0.99
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
it "should parse object without relations from schema" do
|
50
|
+
obj_hash = SK::Api::Schema.to_hash_from_schema(@invoice, 'v1.0')
|
51
|
+
obj_hash.should == {"invoice"=>{"number"=>"911", "line_items"=>[], "title"=>"Your Invoice", "id"=>"some-uuid", "date"=>nil, "client"=>nil, "due_date"=>nil}}
|
52
|
+
client_obj_hash = SK::Api::Schema.to_hash_from_schema(@client, 'v1.0')
|
53
|
+
client_obj_hash.should == {"client"=>{"number"=>"911", "addresses"=>[], "id"=>"some-uuid", "organisation"=>"Dirty Food Inc.", "last_name"=>nil}}
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should parse object with relations from schema" do
|
57
|
+
@invoice.line_items = [@item]
|
58
|
+
@invoice.client = @client
|
59
|
+
obj_hash = SK::Api::Schema.to_hash_from_schema(@invoice, 'v1.0')
|
60
|
+
obj_hash.should == {"invoice"=>{"number"=>"911", "line_items"=>[{"line_item"=>{"position"=>1, "name"=>"Pork Chops", "id"=>"some-uuid", "description"=>"Yummi Pork chopped by mexian emigrants", "price_single"=>0.99}}], "title"=>"Your Invoice", "id"=>"some-uuid", "date"=>nil, "client"=>{"client"=>{"number"=>"911", "addresses"=>[], "id"=>"some-uuid", "organisation"=>"Dirty Food Inc.", "last_name"=>nil}}, "due_date"=>nil}}
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
################################################################################
|
66
|
+
# virtual classes used in test
|
67
|
+
class Invoice
|
68
|
+
attr_accessor :id, :title, :description, :number, :date, :due_date, :line_items, :client
|
69
|
+
end
|
70
|
+
|
71
|
+
class LineItem
|
72
|
+
attr_accessor :id, :name, :description, :position, :price_single
|
73
|
+
end
|
74
|
+
class Client
|
75
|
+
attr_accessor :id, :organisation, :last_name, :number, :addresses
|
76
|
+
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sk_api_schema
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Georg Leciejewski
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-11-
|
18
|
+
date: 2010-11-11 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -60,15 +60,15 @@ files:
|
|
60
60
|
- Rakefile
|
61
61
|
- VERSION
|
62
62
|
- json/v1.0/address.json
|
63
|
+
- json/v1.0/attachment.json
|
63
64
|
- json/v1.0/client.json
|
64
65
|
- json/v1.0/credit_note.json
|
65
66
|
- json/v1.0/invoice.json
|
66
67
|
- json/v1.0/line_item.json
|
67
68
|
- lib/sk_api_schema.rb
|
68
|
-
- lib/utils/serializer.rb
|
69
69
|
- sk_api_schema.gemspec
|
70
|
+
- spec/sk_api_schema_spec.rb
|
70
71
|
- spec/spec_helper.rb
|
71
|
-
- spec/utils/field_map_spec.rb
|
72
72
|
has_rdoc: true
|
73
73
|
homepage: http://github.com/salesking/sk_api_schema
|
74
74
|
licenses: []
|
@@ -105,4 +105,4 @@ specification_version: 3
|
|
105
105
|
summary: SalesKing API JSON Schema
|
106
106
|
test_files:
|
107
107
|
- spec/spec_helper.rb
|
108
|
-
- spec/
|
108
|
+
- spec/sk_api_schema_spec.rb
|
data/lib/utils/serializer.rb
DELETED
@@ -1,66 +0,0 @@
|
|
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
|
@@ -1,73 +0,0 @@
|
|
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
|