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 ADDED
@@ -0,0 +1,3 @@
1
+ nbproject/*
2
+ coverage/*
3
+ rdoc/*
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,3 @@
1
+ Patches for activerecord as long as the 3.0 version is not out
2
+
3
+ * parse error from json response
@@ -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