sk-api 1.0.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 +3 -0
- data/MIT-LICENSE +20 -0
- data/Manifest +30 -0
- data/README.rdoc +42 -0
- data/Rakefile +48 -0
- data/VERSION +1 -0
- data/init.rb +1 -0
- data/lib/activeresource_patches/README +3 -0
- data/lib/activeresource_patches/base.rb +23 -0
- data/lib/activeresource_patches/validations.rb +30 -0
- data/lib/resources/address.rb +35 -0
- data/lib/resources/base.rb +24 -0
- data/lib/resources/client.rb +62 -0
- data/lib/resources/credit_note.rb +49 -0
- data/lib/resources/line_item.rb +32 -0
- data/lib/resources/product.rb +43 -0
- data/lib/sk_api.rb +30 -0
- data/lib/utils/field_map.rb +114 -0
- data/lib/utils/serializer.rb +62 -0
- data/lib/version.rb +9 -0
- data/spec/resources/client_spec.rb +111 -0
- data/spec/resources/credit_note_spec.rb +116 -0
- data/spec/resources/product_spec.rb +77 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/utils/field_map_spec.rb +73 -0
- data/tasks/sk_api_tasks.rake +4 -0
- data/vendor/jsonschema-1.0.0/README.rdoc +94 -0
- data/vendor/jsonschema-1.0.0/Rakefile +94 -0
- data/vendor/jsonschema-1.0.0/lib/jsonschema.rb +434 -0
- data/vendor/jsonschema-1.0.0/ruby-jsonschema.gemspec +31 -0
- data/vendor/jsonschema-1.0.0/test/jsonschema_test.rb +802 -0
- metadata +107 -0
data/.gitignore
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Georg Leciejewski
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
MIT-LICENSE
|
2
|
+
README.rdoc
|
3
|
+
Rakefile
|
4
|
+
init.rb
|
5
|
+
lib/activeresource_patches/README
|
6
|
+
lib/activeresource_patches/base.rb
|
7
|
+
lib/activeresource_patches/validations.rb
|
8
|
+
lib/resources/address.rb
|
9
|
+
lib/resources/base.rb
|
10
|
+
lib/resources/client.rb
|
11
|
+
lib/resources/credit_note.rb
|
12
|
+
lib/resources/line_item.rb
|
13
|
+
lib/sk_api.rb
|
14
|
+
lib/utils/field_map.rb
|
15
|
+
lib/utils/serializer.rb
|
16
|
+
lib/version.rb
|
17
|
+
nbproject/private/private.properties
|
18
|
+
nbproject/project.properties
|
19
|
+
nbproject/project.xml
|
20
|
+
spec/resources/client_spec.rb
|
21
|
+
spec/resources/credit_note_spec.rb
|
22
|
+
spec/spec_helper.rb
|
23
|
+
spec/utils/field_map_spec.rb
|
24
|
+
tasks/sk_api_tasks.rake
|
25
|
+
vendor/jsonschema-1.0.0/README.rdoc
|
26
|
+
vendor/jsonschema-1.0.0/Rakefile
|
27
|
+
vendor/jsonschema-1.0.0/lib/jsonschema.rb
|
28
|
+
vendor/jsonschema-1.0.0/ruby-jsonschema.gemspec
|
29
|
+
vendor/jsonschema-1.0.0/test/jsonschema_test.rb
|
30
|
+
Manifest
|
data/README.rdoc
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
= SalesKing Api
|
2
|
+
|
3
|
+
This plugin is used internally by SalesKing to deliver the API and
|
4
|
+
can be used externally as an API client.
|
5
|
+
|
6
|
+
The SalesKing API client uses ActiveResource, ,with some little build in
|
7
|
+
fixes due to json parsing. For now it only supports JSON, XML comes later.
|
8
|
+
|
9
|
+
To be able to use the API you must have an SalesKing account and API access.
|
10
|
+
Than you can start writing your own middelware-stack.
|
11
|
+
|
12
|
+
== Upcomming
|
13
|
+
|
14
|
+
The code is used in production, but still there is a lot to come, so if you
|
15
|
+
try to use it please tell us, so we can give you API access and support.
|
16
|
+
|
17
|
+
With the rails 3.0 release we are going to pack this code as gem for
|
18
|
+
easier delivery & bundling
|
19
|
+
|
20
|
+
== Example
|
21
|
+
|
22
|
+
client = SkApi::Resources::Client.new(:last_name=>'Eder')
|
23
|
+
client.first_name = "Meister"
|
24
|
+
client.save
|
25
|
+
|
26
|
+
For more take a look into the specs.
|
27
|
+
|
28
|
+
== Salesking API Resources
|
29
|
+
|
30
|
+
Right now there are only two resources available:
|
31
|
+
|
32
|
+
* clients
|
33
|
+
* credit_notes
|
34
|
+
|
35
|
+
== Tests
|
36
|
+
|
37
|
+
To run the test you must insert some credentials into the spec helper.
|
38
|
+
We will gladly provide you with a test account on one of our development
|
39
|
+
systems.
|
40
|
+
|
41
|
+
|
42
|
+
Copyright (c) 2009, 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"
|
10
|
+
gem.summary = %Q{Interact with SalesKing}
|
11
|
+
gem.description = %Q{Interact with SalesKing}
|
12
|
+
gem.email = "gl@salesking.eu"
|
13
|
+
gem.homepage = "http://github.com/salesking/sk-api"
|
14
|
+
gem.authors = ["Georg Leciejewski"]
|
15
|
+
gem.add_development_dependency "rspec", ">= 0"
|
16
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
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 documentation.'
|
42
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
43
|
+
rdoc.rdoc_dir = 'rdoc'
|
44
|
+
rdoc.title = 'SalesKing-Api'
|
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
|
+
1.0.0
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/lib/sk_api"
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module ActiveResource
|
2
|
+
# Overridden methods to suit SalesKing.
|
3
|
+
# Some changes might be kicked when AR 3.0 is out
|
4
|
+
class Base
|
5
|
+
|
6
|
+
# override encode because json is also returned nested by SalesKing
|
7
|
+
def encode(options={})
|
8
|
+
case self.class.format
|
9
|
+
when ActiveResource::Formats[:xml]
|
10
|
+
self.class.format.encode(attributes, {:root => self.class.element_name}.merge(options))
|
11
|
+
else # json also nested
|
12
|
+
self.class.format.encode( {self.class.element_name => attributes}, options)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# override ARes method to parse only the client part
|
17
|
+
def load_attributes_from_response(response)
|
18
|
+
if response['Content-Length'] != "0" && response.body.strip.size > 0
|
19
|
+
load( self.class.format.decode(response.body)[self.class.element_name] )
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module ActiveResource
|
2
|
+
|
3
|
+
module Validations
|
4
|
+
# Validate a resource and save (POST) it to the remote web service.
|
5
|
+
def save_with_validation
|
6
|
+
save_without_validation
|
7
|
+
true
|
8
|
+
rescue ResourceInvalid => error
|
9
|
+
case error.response['Content-Type']
|
10
|
+
when /xml/ #PATCH
|
11
|
+
errors.from_xml(error.response.body)
|
12
|
+
when /json/ #PATCH
|
13
|
+
errors.from_json(error.response.body)
|
14
|
+
end
|
15
|
+
false
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Errors
|
20
|
+
|
21
|
+
# Patched cause we dont need no attribute name magic .. and its just simpler
|
22
|
+
def from_array(messages)
|
23
|
+
clear
|
24
|
+
messages.each do |msg|
|
25
|
+
add msg[0], msg[1]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end #Errors
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module SKApi
|
2
|
+
module Resources
|
3
|
+
class Address < SKApi::Resources::Base
|
4
|
+
|
5
|
+
def save
|
6
|
+
save_with_validation
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.schema
|
10
|
+
{ "type" => "object",
|
11
|
+
"properties" => SKApi::Resources::Address.schema_props}
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.schema_props
|
15
|
+
{
|
16
|
+
"id" => {"type" => "string", "identity" => true, "readonly" => true},
|
17
|
+
"address1" => {"type" => "string", "optional" => true},
|
18
|
+
"address2" => {"type" => "string", "optional" => true},
|
19
|
+
"city" => {"type" => "string", "optional" => true},
|
20
|
+
"country" => {"type" => "string", "optional" => true},
|
21
|
+
"state" => {"type" => "string", "optional" => true},
|
22
|
+
"zip" => {"type" => "string", "optional" => true},
|
23
|
+
"pobox" => {"type" => "string", "optional" => true},
|
24
|
+
"long" => {"type" => "string", "optional" => true},
|
25
|
+
"lat" => {"type" => "string", "optional" => true},
|
26
|
+
"address_type" => {"type" => "string", "optional" => true},
|
27
|
+
"created_at" => {"type" => "string", "format" =>"date-time", "readonly"=> true},
|
28
|
+
"updated_at" => {"type" => "string", "format" =>"date-time", "readonly"=> true},
|
29
|
+
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module SKApi
|
2
|
+
module Resources
|
3
|
+
|
4
|
+
class Base < ActiveResource::Base
|
5
|
+
include SKApi::Utils::Serializer
|
6
|
+
self.format = :json # bug in AR must be set here
|
7
|
+
|
8
|
+
def initialize(attributes = {})
|
9
|
+
# json comes in nested {client={data}
|
10
|
+
attr = attributes[self.class.element_name] || attributes
|
11
|
+
super(attr)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Define the connection to be used when talking to a salesking server
|
15
|
+
def self.set_connection(opts)
|
16
|
+
self.site = opts[:site] #"http://demo.salesking.local:3000/api/"
|
17
|
+
self.user = opts[:user] # "demo@salesking.eu"
|
18
|
+
self.password = opts[:password] #"demo"
|
19
|
+
self.format = opts[:format].to_sym #:json
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module SKApi
|
2
|
+
module Resources
|
3
|
+
class Client < SKApi::Resources::Base
|
4
|
+
|
5
|
+
def save
|
6
|
+
# validate_schema
|
7
|
+
save_with_validation
|
8
|
+
end
|
9
|
+
|
10
|
+
# not realy stable yet
|
11
|
+
def validate_schema
|
12
|
+
json = self.to_json
|
13
|
+
obj = Rufus::Json.decode(json)
|
14
|
+
JSON::Schema.validate(obj, SKApi::Resources::Client.schema)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.schema
|
18
|
+
{ "type" => "object",
|
19
|
+
"properties" => SKApi::Resources::Client.schema_props}
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.schema_props
|
23
|
+
{
|
24
|
+
"id" => {"type" => "string", "identity" => true , "readonly" => true},
|
25
|
+
"number" => {"type" => "string", "optional" => true},
|
26
|
+
"organisation" => {"type" => "string"},
|
27
|
+
"first_name" => {"type" => "string", "optional" => true},
|
28
|
+
"last_name" => {"type" => "string", "optional" => true},
|
29
|
+
"title" => {"type" => "string", "optional" => true},
|
30
|
+
"position" => {"type" => "string", "optional" => true},
|
31
|
+
"gender" => {"type" => "string", "enum" => ["male", "female"] , "optional" => true},
|
32
|
+
"email" => {"type" => "string", "optional" => true},
|
33
|
+
"birthday" => {"type" => "string", "format" =>"date", "optional" => true},
|
34
|
+
"url" => {"type" => "string", "optional" => true},
|
35
|
+
"phone_fax" => {"type" => "string", "optional" => true},
|
36
|
+
"phone_mobile" => {"type" => "string", "optional" => true},
|
37
|
+
"phone_office" => {"type" => "string", "optional" => true},
|
38
|
+
"phone_home" => {"type" => "string", "optional" => true},
|
39
|
+
"bank_owner" => {"type" => "string", "optional" => true},
|
40
|
+
"bank_name" => {"type" => "string", "optional" => true},
|
41
|
+
"bank_number" => {"type" => "string", "optional" => true},
|
42
|
+
"bank_account_number" => {"type" => "string", "optional" => true},
|
43
|
+
"bank_iban" => {"type" => "string", "optional" => true},
|
44
|
+
"bank_swift" => {"type" => "string", "optional" => true},
|
45
|
+
"vat_number" => {"type" => "string", "optional" => true},
|
46
|
+
"tax_number" => {"type" => "string", "optional" => true},
|
47
|
+
"tag_list" => {"type" => "string", "optional" => true},
|
48
|
+
"cash_discount" => {"type" => "number", "optional" => true},
|
49
|
+
"due_days" => {"type" => "integer", "optional" => true},
|
50
|
+
"payment_method" => {"type" => "string", "enum" => ["draft", "open", "closed"], "optional" => true},
|
51
|
+
"sending_method" => {"type" => "string", "enum" => ["draft", "open", "closed"], "optional" => true},
|
52
|
+
"lock_version" => {"type" => "integer", "readonly" => true, "optional" => true},
|
53
|
+
"created_at" => {"type" => "string", "format" =>"date-time", "optional" => true, "readonly" => true},
|
54
|
+
"updated_at" => {"type" => "string", "format" =>"date-time", "optional" => true, "readonly" => true},
|
55
|
+
"address_field" => {"type" => "string", "optional" => true, "readonly" => true},
|
56
|
+
"addresses" => {"type" => "array"},
|
57
|
+
}
|
58
|
+
end #schema_props
|
59
|
+
|
60
|
+
end #Client
|
61
|
+
end #Resources
|
62
|
+
end #SKApi
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module SKApi
|
2
|
+
module Resources
|
3
|
+
class CreditNote < SKApi::Resources::Base
|
4
|
+
|
5
|
+
def save
|
6
|
+
save_with_validation
|
7
|
+
end
|
8
|
+
|
9
|
+
##########################################################################
|
10
|
+
# Class methods
|
11
|
+
##########################################################################
|
12
|
+
|
13
|
+
def self.schema
|
14
|
+
{ "type" => "object",
|
15
|
+
"properties" => SKApi::Resources::CreditNote.schema_props}
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.schema_props
|
19
|
+
{
|
20
|
+
"id" => {"type" => "string", "identity" => true, "optional" => true, "readonly" => true},
|
21
|
+
"number" => {"type" => "string", "optional" => true},
|
22
|
+
"date" => {"type" => "string", "format" =>"date", "optional" => true},
|
23
|
+
"due_days" => {"type" => "integer", "optional" => true},
|
24
|
+
"title" => {"type" => "string", "optional" => true},
|
25
|
+
"status" => {"type" => "string", "enum" => ["draft", "open", "closed"], "default" =>"draft", "optional" => true},
|
26
|
+
"payment_method" => {"type" => "string", "enum" => ["cash", "bank_transfer", "credit_card", "paypal", "direct_debit", "cheque"], "optional" => true},
|
27
|
+
"due_date" => {"type" => "string", "format" =>"date", "optional" => true},
|
28
|
+
"notes_before" => {"type" => "string", "optional" => true},
|
29
|
+
"notes_after" => {"type" => "string", "optional" => true},
|
30
|
+
"price_total" => {"type" => "number", "optional" => true, "readonly" => true},
|
31
|
+
"price_tax" => {"type" => "number", "optional" => true, "readonly" => true},
|
32
|
+
"created_at" => {"type" => "string", "format" =>"date-time", "optional" => true, "readonly"=> true},
|
33
|
+
"updated_at" => {"type" => "string", "format" =>"date-time", "optional" => true, "readonly"=> true},
|
34
|
+
"address_field" => {"type" => "string", "optional" => true, "readonly" => true},
|
35
|
+
"lock_version" => {"type" => "integer", "optional" => true, "readonly" => true},
|
36
|
+
"client_id" => {"type" => "string"},
|
37
|
+
"client" => {"type" => "object", "properties" => SKApi::Resources::Client.schema_props, "optional" => true, "readonly" => true},
|
38
|
+
"line_items" => {"type" => "array","properties" => SKApi::Resources::LineItem.schema_props, "optional" => true,},
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.api_links
|
43
|
+
#internal links on fields=> id => salesking.eu/clients/4567.json
|
44
|
+
#external links to actions and related objects => invoeis => salesking.eu/clients/4567/invoices.json
|
45
|
+
[:edit, :destroy, :copy, :print, :show, :payments, :payment_new]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module SKApi
|
2
|
+
module Resources
|
3
|
+
class LineItem < SKApi::Resources::Base
|
4
|
+
|
5
|
+
def save
|
6
|
+
save_with_validation
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.schema
|
10
|
+
{ "type" => "object",
|
11
|
+
"properties" => SKApi::Resources::LineItem.schema_props}
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.schema_props
|
15
|
+
{
|
16
|
+
"id" => {"type" => "string", "identity" => true , "readonly" => true},
|
17
|
+
"position" => {"type" => "integer"},
|
18
|
+
"product_id" => {"type" => "string", "optional" => true},
|
19
|
+
"quantity" => {"type" => "number"},
|
20
|
+
"quantity_unit" => {"type" => "string", "optional" => true},
|
21
|
+
"name" => {"type" => "string", "optional" => true},
|
22
|
+
"description" => {"type" => "string", "optional" => true},
|
23
|
+
"price_single" => {"type" => "number"},
|
24
|
+
"discount" => {"type" => "number", "optional" => true},
|
25
|
+
"tax" => {"type" => "number", "optional" => true},
|
26
|
+
"created_at" => {"type" => "string", "format" =>"date-time", "optional" => true, "readonly" => true},
|
27
|
+
"updated_at" => {"type" => "string", "format" =>"date-time", "optional" => true, "readonly" => true}
|
28
|
+
}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module SKApi
|
2
|
+
module Resources
|
3
|
+
class Product < SKApi::Resources::Base
|
4
|
+
|
5
|
+
def save
|
6
|
+
# validate_schema
|
7
|
+
save_with_validation
|
8
|
+
end
|
9
|
+
|
10
|
+
# not realy stable yet
|
11
|
+
def validate_schema
|
12
|
+
json = self.to_json
|
13
|
+
obj = Rufus::Json.decode(json)
|
14
|
+
JSON::Schema.validate(obj, SKApi::Resources::Product.schema)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.schema
|
18
|
+
{ "type" => "object",
|
19
|
+
"properties" => SKApi::Resources::Product.schema_props}
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.schema_props
|
23
|
+
{
|
24
|
+
# category
|
25
|
+
# template_id
|
26
|
+
"id" => {"type" => "string", "identity" => true , "readonly" => true},
|
27
|
+
"number" => {"type" => "string", "optional" => true},
|
28
|
+
"name" => {"type" => "string"},
|
29
|
+
"description" => {"type" => "string", "optional" => true},
|
30
|
+
"price" => {"type" => "number"},
|
31
|
+
"tax" => {"type" => "number", "optional" => true},
|
32
|
+
"quantity_unit"=> {"type" => "string", "optional" => true},
|
33
|
+
"tag_list" => {"type" => "string", "optional" => true},
|
34
|
+
"lock_version" => {"type" => "integer", "readonly" => true, "optional" => true},
|
35
|
+
"published_at" => {"type" => "string", "format" =>"date", "optional" => true},
|
36
|
+
"created_at" => {"type" => "string", "format" =>"date-time", "optional" => true, "readonly" => true},
|
37
|
+
"updated_at" => {"type" => "string", "format" =>"date-time", "optional" => true, "readonly" => true},
|
38
|
+
}
|
39
|
+
end #schema_props
|
40
|
+
|
41
|
+
end #Product
|
42
|
+
end #Resources
|
43
|
+
end #SKApi
|
data/lib/sk_api.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# external
|
2
|
+
require 'active_resource'
|
3
|
+
unless RUBY_PLATFORM =~ /java/
|
4
|
+
require 'yajl'
|
5
|
+
require 'rufus-json'
|
6
|
+
|
7
|
+
Rufus::Json.backend = :yajl
|
8
|
+
else
|
9
|
+
require 'json'
|
10
|
+
require 'rufus-json'
|
11
|
+
|
12
|
+
Rufus::Json.backend = :json
|
13
|
+
end
|
14
|
+
|
15
|
+
#vendored
|
16
|
+
require File.dirname(__FILE__) + '/../vendor/jsonschema-1.0.0/lib/jsonschema'
|
17
|
+
|
18
|
+
# utilities
|
19
|
+
require File.dirname(__FILE__) + '/utils/field_map'
|
20
|
+
require File.dirname(__FILE__) + '/utils/serializer'
|
21
|
+
|
22
|
+
#resources
|
23
|
+
require File.dirname(__FILE__) + '/activeresource_patches/validations'
|
24
|
+
require File.dirname(__FILE__) + '/activeresource_patches/base'
|
25
|
+
require File.dirname(__FILE__) + '/resources/base'
|
26
|
+
require File.dirname(__FILE__) + '/resources/product'
|
27
|
+
require File.dirname(__FILE__) + '/resources/client'
|
28
|
+
require File.dirname(__FILE__) + '/resources/address'
|
29
|
+
require File.dirname(__FILE__) + '/resources/credit_note'
|
30
|
+
require File.dirname(__FILE__) + '/resources/line_item'
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module SKApi
|
2
|
+
module Utils
|
3
|
+
# Provide methods for mapping the fields of a remote object to local object
|
4
|
+
# The class holds two objects (f.ex. a remote and a local object) and works
|
5
|
+
# with a hash which maps the fields between those two.
|
6
|
+
# If you use such a mapping both of your objects MUST respond to the method
|
7
|
+
# names passed in the mapping-table(hash)
|
8
|
+
#
|
9
|
+
# When an object is updated you can check the #log for changes
|
10
|
+
# ==== Example
|
11
|
+
#
|
12
|
+
# contact_map = {
|
13
|
+
# :loc_key => :name,
|
14
|
+
# :rem_key => :firstname,
|
15
|
+
# :obj => 'Stanza::SalesKing::Mapping::ContactTrans',
|
16
|
+
# :loc_trans=>:set_local_name,
|
17
|
+
# :rem_trans=> :set_remote_name
|
18
|
+
# }
|
19
|
+
# map = SKApi::Utils::FieldMap.new(@local_user, @remote_user, contact_map)
|
20
|
+
# map.update_remote #Does not save! only sets the field values on the remote object
|
21
|
+
#
|
22
|
+
# ==== Mapping Hash Explanation
|
23
|
+
#
|
24
|
+
# {
|
25
|
+
# :loc_key => :name, => Local fieldname #
|
26
|
+
# :rem_key => :firstname, => remote fieldname
|
27
|
+
# :obj => 'ATransitionClass', => The class which hold the following Transition methods as Class.methods
|
28
|
+
# :loc_trans=>:set_local_name, => Method called when local field is updated
|
29
|
+
# :rem_trans=> :set_remote_name => Method called when remote field is update
|
30
|
+
# }
|
31
|
+
class FieldMap
|
32
|
+
|
33
|
+
# The local object
|
34
|
+
attr_accessor :loc_obj
|
35
|
+
# The remote object
|
36
|
+
attr_accessor :rem_obj
|
37
|
+
# <Hash{Symbol=>Symbol, Symbol=>{Hash} }>::the field mapping
|
38
|
+
attr_accessor :fields
|
39
|
+
# the outdated fields
|
40
|
+
attr_reader :outdated
|
41
|
+
# <Array[String]>::log field changes
|
42
|
+
attr_reader :log
|
43
|
+
|
44
|
+
# Takes a local and remote object which should respond to function defined
|
45
|
+
# in the mapping hash
|
46
|
+
def initialize(loc_obj, rem_obj, fields)
|
47
|
+
@loc_obj = loc_obj
|
48
|
+
@rem_obj = rem_obj
|
49
|
+
@fields = fields
|
50
|
+
@log = []
|
51
|
+
end
|
52
|
+
|
53
|
+
# check if the any of the fields are outdated
|
54
|
+
# populates self.outdated array with outdated fields
|
55
|
+
# ==== Returns
|
56
|
+
# <Boolean>:: false if not outdated
|
57
|
+
def outdated?
|
58
|
+
@outdated = []
|
59
|
+
fields.each do |fld|
|
60
|
+
if fld[:trans]
|
61
|
+
# SomeTransferObject.remote_tranfer_function(remote_obj_data)
|
62
|
+
virtual_local_val = fld[:trans][:obj].constantize.send( fld[:trans][:rem_trans], loc_obj.send( fld[:loc_key] ) )
|
63
|
+
@outdated << fld if virtual_local_val != rem_obj.send( fld[:rem_key] )
|
64
|
+
else
|
65
|
+
@outdated << fld if rem_obj.send( fld[:rem_key] ) != loc_obj.send( fld[:loc_key] )
|
66
|
+
end
|
67
|
+
end
|
68
|
+
!@outdated.empty?
|
69
|
+
end
|
70
|
+
|
71
|
+
# update all local outdated fields wit hvcalues from remote object
|
72
|
+
def update_local_outdated
|
73
|
+
update_local(@outdated) if outdated?
|
74
|
+
end
|
75
|
+
# update all remote outdated fields wit hvalues from local object
|
76
|
+
def update_remote_outdated
|
77
|
+
update_remote(@outdated) if outdated?
|
78
|
+
end
|
79
|
+
|
80
|
+
# update all local fields with values from remote
|
81
|
+
def update_local(field=nil)
|
82
|
+
flds = field ? ( field.is_a?(Array) ? field : [field] ) : fields
|
83
|
+
flds.each do |fld|
|
84
|
+
old_val = loc_obj.send(fld[:loc_key]) rescue 'empty'
|
85
|
+
new_val = if fld[:trans] #call transfer function
|
86
|
+
fld[:trans][:obj].constantize.send( fld[:trans][:loc_trans], rem_object.send( fld[:rem_key] ) )
|
87
|
+
else # lookup directly on local object
|
88
|
+
rem_obj.send(fld[:rem_key])
|
89
|
+
end
|
90
|
+
loc_obj.send( "#{fld[:loc_key]}=", new_val )
|
91
|
+
# write to log
|
92
|
+
log << "local: #{fld[:loc_key]} was: #{old_val} updated from remote: #{fld[:rem_key]} with value: #{new_val}"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Update all or given remote fields with the value of the local fields
|
97
|
+
#
|
98
|
+
def update_remote(field=nil)
|
99
|
+
flds = field ? ( field.is_a?(Array) ? field : [field] ) : fields
|
100
|
+
flds.each do |fld|
|
101
|
+
old_val = rem_obj.send(fld[:rem_key]) rescue 'empty'# rember for log
|
102
|
+
new_val = if fld[:trans] #call transfer function
|
103
|
+
fld[:trans][:obj].constantize.send( fld[:trans][:rem_trans], loc_obj.send( fld[:loc_key] ) )
|
104
|
+
else # lookup directly on local object
|
105
|
+
loc_obj.send( fld[:loc_key] )
|
106
|
+
end
|
107
|
+
rem_obj.send( "#{fld[:rem_key]}=" , new_val )
|
108
|
+
log << "remote: #{fld[:rem_key]} was: #{old_val} updated from local: #{fld[:loc_key]} with value: #{new_val}"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
end # FieldMapping
|
113
|
+
end # Utils
|
114
|
+
end #SKApi
|