sk-api 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|