sugarcrm 0.9.9 → 0.9.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/README.rdoc +9 -14
  2. data/Rakefile +2 -10
  3. data/VERSION +1 -1
  4. data/lib/sugarcrm.rb +1 -0
  5. data/lib/sugarcrm/associations/association.rb +91 -29
  6. data/lib/sugarcrm/associations/association_methods.rb +1 -2
  7. data/lib/sugarcrm/associations/associations.rb +10 -16
  8. data/lib/sugarcrm/attributes/attribute_typecast.rb +7 -0
  9. data/lib/sugarcrm/connection/api/get_available_modules.rb +1 -1
  10. data/lib/sugarcrm/connection/api/get_document_revision.rb +2 -2
  11. data/lib/sugarcrm/connection/api/get_entries.rb +5 -5
  12. data/lib/sugarcrm/connection/api/get_entries_count.rb +4 -4
  13. data/lib/sugarcrm/connection/api/get_entry.rb +5 -5
  14. data/lib/sugarcrm/connection/api/get_entry_list.rb +9 -9
  15. data/lib/sugarcrm/connection/api/get_module_fields.rb +2 -2
  16. data/lib/sugarcrm/connection/api/get_note_attachment.rb +3 -3
  17. data/lib/sugarcrm/connection/api/get_relationships.rb +8 -8
  18. data/lib/sugarcrm/connection/api/get_report_entries.rb +3 -3
  19. data/lib/sugarcrm/connection/api/get_user_id.rb +1 -1
  20. data/lib/sugarcrm/connection/api/get_user_team_id.rb +1 -1
  21. data/lib/sugarcrm/connection/api/logout.rb +2 -2
  22. data/lib/sugarcrm/connection/api/seamless_login.rb +1 -1
  23. data/lib/sugarcrm/connection/api/search_by_module.rb +5 -5
  24. data/lib/sugarcrm/connection/api/set_campaign_merge.rb +3 -3
  25. data/lib/sugarcrm/connection/api/set_document_revision.rb +3 -3
  26. data/lib/sugarcrm/connection/api/set_entries.rb +3 -3
  27. data/lib/sugarcrm/connection/api/set_entry.rb +3 -3
  28. data/lib/sugarcrm/connection/api/set_note_attachment.rb +24 -2
  29. data/lib/sugarcrm/connection/api/set_relationship.rb +7 -7
  30. data/lib/sugarcrm/connection/api/set_relationships.rb +5 -5
  31. data/lib/sugarcrm/connection/connection.rb +3 -1
  32. data/lib/sugarcrm/environment.rb +16 -1
  33. data/test/connection/test_get_entry_list.rb +1 -1
  34. data/test/connection/test_set_note_attachment.rb +17 -0
  35. data/test/helper.rb +1 -1
  36. data/test/test_associations.rb +98 -0
  37. data/test/test_environment.rb +7 -0
  38. data/test/test_sugarcrm.rb +0 -52
  39. metadata +29 -36
  40. data/test/test_association.rb +0 -18
data/README.rdoc CHANGED
@@ -6,13 +6,7 @@ REST Bindings for SugarCRM!
6
6
 
7
7
  == SUMMARY:
8
8
 
9
- RubyGem for interacting with SugarCRM via REST.
10
-
11
- == Description:
12
-
13
- A less clunky way to interact with SugarCRM via REST.
14
-
15
- Instead of SugarCRM.connection.get_entry("Users", "1") you could use SugarCRM::User.find(1). There is support for collections à la SugarCRM::User.find(1).email_addresses, or SugarCRM::Contact.first.meetings << new_meeting. ActiveRecord style finders are in place, with limited support for conditions and joins.
9
+ A less clunky way to interact with SugarCRM via REST.
16
10
 
17
11
  == FEATURES/PROBLEMS:
18
12
 
@@ -145,12 +139,13 @@ Instead of SugarCRM.connection.get_entry("Users", "1") you could use SugarCRM::U
145
139
 
146
140
  == USING A CONFIGURATION FILE
147
141
 
148
- If you want to use a configuration file instead of always specifying the url, username, and password to connect to SugarCRM, you can either
142
+ If you want to use a configuration file instead of always specifying the url, username, and password to connect to SugarCRM, you can add your credentials to one (or more) of
149
143
 
150
- * add your credentials to `/etc/sugarcrm.yaml`
151
- * add your credentials to `~/.sugarcrm.yaml`
152
- * add your credentials to `config/sugarcrm.yaml` (will need to be copied each time you upgrade or reinstall the gem)
153
- * add your credentials to a YAML file and call `SugarCRM::Environment.load_config` followed by the absolute path to your configuration file
144
+ * `/etc/sugarcrm.yaml`
145
+ * `~/.sugarcrm.yaml` (i.e. your home directory on Linux and Mac OSX)
146
+ * a `sugarcrm.yaml` file at the root of you Windows home directory (execute `ENV['USERPROFILE']` in Ruby to see which directory should contain the file)
147
+ * `config/sugarcrm.yaml` (will need to be copied each time you upgrade or reinstall the gem)
148
+ * a YAML file and call `SugarCRM::Environment.load_config` followed by the absolute path to your configuration file
154
149
 
155
150
  If there are several configuration files, they are loaded sequentially in the order above and will overwrite previous values (if present). This allows you to (e.g.) have a config file in `/etc/sugarcrm.yaml` with system-wide configuration information (such as the url where SugarCRM is located) and/or defaults. Each developer/user can then have his personal configuration file in `~/.sugarcrm.yaml` with his own username and password. A developer could also specify a different location for the SugarCRM instance (e.g. a local testing instance) in his configuration file, which will take precedence over the value in `/etc/sugarcrm.yaml`.
156
151
 
@@ -175,9 +170,9 @@ An example, accompanied by instructions, can be found in the `config/sugarcrm.ya
175
170
 
176
171
  4. You now have full access to the gem's functionality, e.g. `puts SugarCRM::Account.first.name`
177
172
 
178
- == EXPANDING THE GEM
173
+ == EXTENDING THE GEM
179
174
 
180
- If you want to expand the gem's capabilities (e.g. to add methods specific to your environment), you can either
175
+ If you want to extend the gem's capabilities (e.g. to add methods specific to your environment), you can either
181
176
 
182
177
  * drop your `*.rb` files in `lib/sugarcrm/extensions/` (see the README in that folder)
183
178
 
data/Rakefile CHANGED
@@ -13,11 +13,10 @@ require 'jeweler'
13
13
  Jeweler::Tasks.new do |gem|
14
14
  # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
15
  gem.name = "sugarcrm"
16
- gem.summary = %Q{Ruby based REST client for SugarCRM}
17
- gem.description = %Q{A less clunky way to interact with SugarCRM via REST. Instead of SugarCRM.connection.get_entry("Users", "1") you could use SugarCRM::User.find(1). There is support for collections a la SugarCRM::User.find(1).email_addresses, or SugarCRM::Contact.first.meetings << new_meeting. ActiveRecord style finders are in place, with limited support for conditions and joins.}
16
+ gem.summary = %Q{A less clunky way to interact with SugarCRM via REST.}
18
17
  gem.email = "carl.hicks@gmail.com"
19
18
  gem.homepage = "http://github.com/chicks/sugarcrm"
20
- gem.authors = ["Carl Hicks"]
19
+ gem.authors = ["Carl Hicks", "David Sulc"]
21
20
  end
22
21
  Jeweler::RubygemsDotOrgTasks.new
23
22
 
@@ -28,13 +27,6 @@ Rake::TestTask.new(:test) do |test|
28
27
  test.verbose = true
29
28
  end
30
29
 
31
- #require 'rcov/rcovtask'
32
- #Rcov::RcovTask.new do |test|
33
- # test.libs << 'test'
34
- # test.pattern = 'test/**/test_*.rb'
35
- # test.verbose = true
36
- #end
37
-
38
30
  task :default => :test
39
31
 
40
32
  require 'rake/rdoctask'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.9.9
1
+ 0.9.10
data/lib/sugarcrm.rb CHANGED
@@ -3,6 +3,7 @@ require 'pp'
3
3
  require 'set'
4
4
  require 'cgi'
5
5
  require 'uri'
6
+ require 'base64'
6
7
  require 'rubygems'
7
8
  require 'active_support/core_ext'
8
9
  require 'json'
@@ -1,21 +1,30 @@
1
1
  module SugarCRM
2
- # Represents an association and it's metadata
2
+
3
+ # Associations are middlemen between the object that holds the association, known as the @owner,
4
+ # and the actual associated object, known as the @target. Methods are added to the @owner that
5
+ # allow access to the association collection, and are held in @proxy_methods. The cardinality
6
+ # of the association is available in @cardinality, and the actual relationship details are held
7
+ # in @relationship.
3
8
  class Association
4
9
  attr :owner, true
5
10
  attr :target, true
6
11
  attr :link_field, true
12
+ attr :relationship, true
7
13
  attr :attributes, true
8
- attr :methods, true
14
+ attr :proxy_methods, true
15
+ attr :cardinality, true
9
16
 
10
- # TODO: Describe this.
17
+ # Creates a new instance of an Association
11
18
  def initialize(owner,link_field,opts={})
12
19
  @options = { :define_methods? => true }.merge! opts
13
20
  @owner = owner
14
21
  check_valid_owner
15
22
  @link_field = link_field
16
23
  @attributes = owner.link_fields[link_field]
24
+ @relationship = relationship_for(@attributes["relationship"])
17
25
  @target = resolve_target
18
- @methods = define_methods if @options[:define_methods?]
26
+ @proxy_methods = define_methods if @options[:define_methods?]
27
+ @cardinality = resolve_cardinality
19
28
  self
20
29
  end
21
30
 
@@ -28,6 +37,27 @@ module SugarCRM
28
37
  false
29
38
  end
30
39
 
40
+ def ==(comparison_object)
41
+ comparison_object.instance_of?(self.class) &&
42
+ @target.class == comparison_object.class &&
43
+ @link_field == comparison_object.link_field
44
+ end
45
+ alias :eql? :==
46
+
47
+ def hash
48
+ "#{@target.class}##{@link_field}".hash
49
+ end
50
+
51
+ def inspect
52
+ self
53
+ end
54
+
55
+ def to_s
56
+ "#<SugarCRM::Association @proxy_methods=[#{@proxy_methods.join(", ")}], " +
57
+ "@link_field=\"#{@link_field}\", @target=#{@target}, @owner=#{@owner.class}, " +
58
+ "@cardinality=#{@cardinality}>"
59
+ end
60
+
31
61
  protected
32
62
 
33
63
  def check_valid_owner
@@ -36,7 +66,6 @@ module SugarCRM
36
66
  end
37
67
 
38
68
  # Attempts to determine the class of the target in the association
39
- # TODO: Write tests for this.
40
69
  def resolve_target
41
70
  # Use the link_field name first
42
71
  klass = @link_field.singularize.camelize
@@ -46,47 +75,80 @@ module SugarCRM
46
75
  module_name = SugarCRM::Module.find(@attributes["module"])
47
76
  return "SugarCRM::#{module_name.klass}".constantize if SugarCRM.const_defined? module_name.klass
48
77
  end
49
- # Use the link_field attribute "relationship"
78
+ # Use the "relationship" target
50
79
  if @attributes["relationship"].length > 0
51
- klass = humanized_link_name(@attributes["relationship"]).singularize.camelize
80
+ klass = @relationship[:target][:name].singularize.camelize
52
81
  return "SugarCRM::#{klass}".constantize if SugarCRM.const_defined? klass
53
82
  end
54
83
  false
55
84
  end
56
85
 
86
+ # Defines methods for accessing the association target on the owner class.
87
+ # If the link_field name includes the owner class name, it is stripped before
88
+ # creating the method. If this occurs, we also create an alias to the stripped
89
+ # method using the full link_field name.
90
+ def define_methods
91
+ methods = []
92
+ pretty_name = @relationship[:target][:name]
93
+ methods << define_method(@link_field)
94
+ methods << define_alias(pretty_name, @link_field) if pretty_name != @link_field
95
+ methods
96
+ end
97
+
57
98
  # Generates the association proxy method for related module
58
99
  def define_method(link_field)
100
+ raise ArgumentException, "argument cannot be nil" if link_field.nil?
101
+ if (@owner.respond_to? link_field.to_sym) && @owner.debug
102
+ warn "Warning: Overriding method: #{@owner.class}##{link_field}"
103
+ end
59
104
  @owner.class.module_eval %Q?
60
105
  def #{link_field}
61
106
  query_association :#{link_field}
62
107
  end
63
108
  ?
109
+ link_field
64
110
  end
65
111
 
66
- # Defines methods for accessing the association target on the owner class.
67
- # If the link_field name includes the owner class name, it is stripped before
68
- # creating the method. If this occurs, we also create an alias to the stripped
69
- # method using the full link_field name.
70
- def define_methods
71
- methods = []
72
- pretty_name = humanized_link_name(@link_field)
73
- methods << define_method(@link_field)
74
- if pretty_name != @link_field
75
- @owner.class.module_eval %Q?
76
- alias :#{pretty_name} #{@link_field}
77
- ?
78
- methods << @link_field
79
- end
80
- methods
112
+ # Defines a method alias. Checks to see if a method is already defined.
113
+ def define_alias(alias_name, method_name)
114
+ @owner.class.module_eval %Q?
115
+ alias :#{alias_name} :#{method_name}
116
+ ?
117
+ alias_name
118
+ end
119
+
120
+ # This method breaks the relationship into parts and returns them
121
+ def relationship_for(relationship)
122
+ # We need to run both regexes, because the plurality of the @owner module name is
123
+ # important
124
+ plural_regex = /((.*)_)?(#{Regexp.quote(@owner.class._module.name.downcase)})(_(.*))?/
125
+ singular_regex = /((.*)_)?(#{Regexp.quote(@owner.class._module.name.downcase.singularize)})(_(.*))?/
126
+ # Break the loop if we match
127
+ [plural_regex, singular_regex].each {|r| break if relationship.match(r)}
128
+ # Assign sane values to things if we didnt match
129
+ o = $3
130
+ o = @owner.class._module.name.downcase if o.nil? || o.empty?
131
+ t = [$2, $5].compact.join('_')
132
+ t = @link_field if t.nil? || t.empty?
133
+ # Look up the cardinality
134
+ o_c, t_c = cardinality_for(o,t)
135
+ {:owner => {:name => o, :cardinality => o_c},
136
+ :target => {:name => t, :cardinality => t_c}}
137
+ end
138
+
139
+ # Determines if the provided string is plural or singular
140
+ # Plurality == Cardinality
141
+ def cardinality_for(*args)
142
+ args.inject([]) {|results,arg|
143
+ result = :many
144
+ result = :one if arg.singularize == arg
145
+ results << result
146
+ }
81
147
  end
82
148
 
83
- # Return the name of the relationship excluding the owner part of the name.
84
- # e.g. if a custom relationship is defined in Studio between Tasks and Documents,
85
- # the link_field will be `tasks_documents` but a human would call the relationship `documents`
86
- def humanized_link_name(link_field)
87
- # the module name is used to function properly with modules containing '_' (e.g. a custom module abc_sale : custom modules need a prefix (abc here) so they will always have a '_' in their table name)
88
- return link_field unless link_field.to_s =~ /((.*)_)?#{Regexp.quote(@owner.class._module.name.downcase)}(_(.*))?/
89
- [$2, $4].compact.join('_')
149
+ # TODO: Add Tests for This
150
+ def resolve_cardinality
151
+ "#{@relationship[:owner][:cardinality]}_to_#{@relationship[:target][:cardinality]}".to_sym
90
152
  end
91
153
 
92
154
  end
@@ -38,7 +38,7 @@ module SugarCRM; module AssociationMethods
38
38
  "Couldn't associate #{self.class._module.name}: #{self.id} -> #{t}: #{t.id}!"
39
39
  end
40
40
  # We need to update the association cache for any changes we make.
41
- if opts[:delete]
41
+ if opts[:delete] == 1
42
42
  update_association_cache_for(association.link_field, t, :delete)
43
43
  t.update_association_cache_for(association.link_field, self, :delete)
44
44
  else
@@ -51,7 +51,6 @@ module SugarCRM; module AssociationMethods
51
51
  alias :relate! :associate!
52
52
 
53
53
  # Removes a relationship between the current object and the target object
54
- # TODO: Write a test for this.
55
54
  def disassociate!(target)
56
55
  associate!(target,{:delete => 1})
57
56
  end
@@ -19,6 +19,13 @@ module SugarCRM
19
19
  self
20
20
  end
21
21
 
22
+ # Returns the proxy methods of all the associations in the collection
23
+ def proxy_methods
24
+ @associations.inject([]) { |pm,a|
25
+ pm = pm | a.proxy_methods
26
+ }
27
+ end
28
+
22
29
  # Looks up an association by object, link_field, or method.
23
30
  # Raises an exception if not found
24
31
  def find!(target)
@@ -32,26 +39,13 @@ module SugarCRM
32
39
  # Returns false if not found
33
40
  def find(association)
34
41
  begin
35
- find!
42
+ find!(association)
36
43
  rescue InvalidAssociation
37
44
  false
38
45
  end
39
46
  end
40
-
41
- def inspect
42
- self
43
- end
44
-
45
- def to_s
46
- methods = []
47
- @associations.each do |a|
48
- a.methods.each do |m|
49
- methods << m
50
- end
51
- end
52
- "[#{methods.join(', ')}]"
53
- end
54
-
47
+ alias :include? :find
48
+
55
49
  # delegate undefined methods to the @collection array
56
50
  # E.g. contact.cases should behave like an array and allow `length`, `size`, `each`, etc.
57
51
  def method_missing(method_name, *args, &block)
@@ -18,6 +18,13 @@ module SugarCRM; module AttributeTypeCast
18
18
  # skip primary key columns
19
19
  next if name == "id"
20
20
  attr_type = attr_type_for(name)
21
+
22
+ # empty attributes should stay empty (e.g. an empty int field shouldn't be typecast as 0)
23
+ if [:datetime, :datetimecombo, :int].include? attr_type && (value.nil? || value == '')
24
+ @attributes[name] = nil
25
+ next
26
+ end
27
+
21
28
  case attr_type
22
29
  when :bool
23
30
  @attributes[name] = (value == "1")
@@ -4,7 +4,7 @@ module SugarCRM; class Connection
4
4
  login! unless logged_in?
5
5
  json = <<-EOF
6
6
  {
7
- \"session\": \"#{@session}\"
7
+ "session": "#{@session}"
8
8
  }
9
9
  EOF
10
10
 
@@ -4,8 +4,8 @@ module SugarCRM; class Connection
4
4
  login! unless logged_in?
5
5
  json = <<-EOF
6
6
  {
7
- \"session\": \"#{@session}\"\,
8
- \"id\": #{id}
7
+ "session": "#{@session}",
8
+ "id": #{id}
9
9
  }
10
10
  EOF
11
11
  json.gsub!(/^\s{6}/,'')
@@ -10,11 +10,11 @@ module SugarCRM; class Connection
10
10
 
11
11
  json = <<-EOF
12
12
  {
13
- \"session\": \"#{@session}\"\,
14
- \"module_name\": \"#{module_name}\"\,
15
- \"ids\": #{ids.to_json}\,
16
- \"select_fields\": #{resolve_fields(module_name, options[:fields])}\,
17
- \"link_name_to_fields_array\": #{options[:link_fields].to_json}
13
+ "session": "#{@session}",
14
+ "module_name": "#{module_name}",
15
+ "ids": #{ids.to_json},
16
+ "select_fields": #{resolve_fields(module_name, options[:fields])},
17
+ "link_name_to_fields_array": #{options[:link_fields].to_json}
18
18
  }
19
19
  EOF
20
20
  json.gsub!(/^\s{6}/,'')
@@ -8,10 +8,10 @@ module SugarCRM; class Connection
8
8
 
9
9
  json = <<-EOF
10
10
  {
11
- \"session\": \"#{@session}\"\,
12
- \"module_name\": \"#{module_name}\"\,
13
- \"query\": \"#{query}\"\,
14
- \"deleted\": #{options[:deleted]}
11
+ "session": "#{@session}",
12
+ "module_name": "#{module_name}",
13
+ "query": "#{query}",
14
+ "deleted": #{options[:deleted]}
15
15
  }
16
16
  EOF
17
17
  json.gsub!(/^\s{6}/,'')
@@ -9,11 +9,11 @@ module SugarCRM; class Connection
9
9
 
10
10
  json = <<-EOF
11
11
  {
12
- \"session\": \"#{@session}\"\,
13
- \"module_name\": \"#{module_name}\"\,
14
- \"id\": \"#{id}\"\,
15
- \"select_fields\": #{resolve_fields(module_name, options[:fields])}\,
16
- \"link_name_to_fields_array\": #{options[:link_fields]}
12
+ "session": "#{@session}",
13
+ "module_name": "#{module_name}",
14
+ "id": "#{id}",
15
+ "select_fields": #{resolve_fields(module_name, options[:fields])},
16
+ "link_name_to_fields_array": #{options[:link_fields]}
17
17
  }
18
18
  EOF
19
19
 
@@ -14,15 +14,15 @@ module SugarCRM; class Connection
14
14
 
15
15
  json = <<-EOF
16
16
  {
17
- \"session\": \"#{@session}\"\,
18
- \"module_name\": \"#{module_name}\"\,
19
- \"query\": \"#{query}\"\,
20
- \"order_by\": \"#{options[:order_by]}\"\,
21
- \"offset\": \"#{options[:offset]}\"\,
22
- \"select_fields\": #{resolve_fields(module_name, options[:fields])}\,
23
- \"link_name_to_fields_array\": #{options[:link_fields].to_json}\,
24
- \"max_results\": \"#{options[:limit]}\"\,
25
- \"deleted\": #{options[:deleted]}
17
+ "session": "#{@session}",
18
+ "module_name": "#{module_name}",
19
+ "query": "#{query}",
20
+ "order_by": "#{options[:order_by]}",
21
+ "offset": "#{options[:offset]}",
22
+ "select_fields": #{resolve_fields(module_name, options[:fields])},
23
+ "link_name_to_fields_array": #{options[:link_fields].to_json},
24
+ "max_results": "#{options[:limit]}",
25
+ "deleted": #{options[:deleted]}
26
26
  }
27
27
  EOF
28
28
  json.gsub!(/^\s{6}/,'')
@@ -4,8 +4,8 @@ module SugarCRM; class Connection
4
4
  login! unless logged_in?
5
5
  json = <<-EOF
6
6
  {
7
- \"session\": \"#{@session}\"\,
8
- \"module_name": \"#{module_name}"
7
+ "session": "#{@session}",
8
+ "module_name": "#{module_name}"
9
9
  }
10
10
  EOF
11
11
  json.gsub!(/^\s{6}/,'')
@@ -4,11 +4,11 @@ module SugarCRM; class Connection
4
4
  login! unless logged_in?
5
5
  json = <<-EOF
6
6
  {
7
- \"session\": \"#{@session}\"\,
8
- \"id\": #{id}\
7
+ "session": "#{@session}",
8
+ "id": "#{id}"
9
9
  }
10
10
  EOF
11
11
  json.gsub!(/^\s{6}/,'')
12
- send!(:get_note_attachment, json)
12
+ send!(:get_note_attachment, json)["note_attachment"]
13
13
  end
14
14
  end; end
@@ -13,14 +13,14 @@ module SugarCRM; class Connection
13
13
 
14
14
  json = <<-EOF
15
15
  {
16
- \"session\": \"#{@session}\"\,
17
- \"module_name\": \"#{module_name}\"\,
18
- \"module_id\": \"#{id}\"\,
19
- \"link_field_name\": \"#{related_to.downcase}\"\,
20
- \"related_module_query\": \"#{options[:query]}\"\,
21
- \"related_fields\": #{resolve_related_fields(module_name, related_to)}\,
22
- \"related_module_link_name_to_fields_array\": #{options[:link_fields].to_json}\,
23
- \"deleted\": #{options[:deleted]}
16
+ "session": "#{@session}",
17
+ "module_name": "#{module_name}",
18
+ "module_id": "#{id}",
19
+ "link_field_name": "#{related_to.downcase}",
20
+ "related_module_query": "#{options[:query]}",
21
+ "related_fields": #{resolve_related_fields(module_name, related_to)},
22
+ "related_module_link_name_to_fields_array": #{options[:link_fields].to_json},
23
+ "deleted": #{options[:deleted]}
24
24
  }
25
25
  EOF
26
26
  json.gsub!(/^\s{6}/,'')
@@ -6,9 +6,9 @@ module SugarCRM; class Connection
6
6
 
7
7
  json = <<-EOF
8
8
  {
9
- \"session\": \"#{@session}\"\,
10
- \"ids\": #{ids.to_json}\,
11
- \"select_fields\": \"#{options[:select_fields].to_json}\"
9
+ "session": "#{@session}",
10
+ "ids": #{ids.to_json},
11
+ "select_fields": "#{options[:select_fields].to_json}"
12
12
  }
13
13
  EOF
14
14
  json.gsub!(/^\s{6}/,'')
@@ -4,7 +4,7 @@ module SugarCRM; class Connection
4
4
  login! unless logged_in?
5
5
  json = <<-EOF
6
6
  {
7
- \"session\": \"#{@session}\"
7
+ "session": "#{@session}"
8
8
  }
9
9
  EOF
10
10
  json.gsub!(/^\s{6}/,'')
@@ -5,7 +5,7 @@ module SugarCRM; class Connection
5
5
  login! unless logged_in?
6
6
  json = <<-EOF
7
7
  {
8
- \"session\": \"#{@session}\"
8
+ "session": "#{@session}"
9
9
  }
10
10
  EOF
11
11
  json.gsub!(/^\s{6}/,'')
@@ -4,8 +4,8 @@ module SugarCRM; class Connection
4
4
  login! unless logged_in?
5
5
  json = <<-EOF
6
6
  {
7
- \"user_auth\": {
8
- \"session\": \"#{@session}\"
7
+ "user_auth": {
8
+ "session": "#{@session}"
9
9
  }
10
10
  }
11
11
  EOF
@@ -4,7 +4,7 @@ module SugarCRM; class Connection
4
4
  login! unless logged_in?
5
5
  json = <<-EOF
6
6
  {
7
- \"session\": \"#{@session}\"
7
+ "session": "#{@session}"
8
8
  }
9
9
  EOF
10
10
  json.gsub!(/^\s{6}/,'')
@@ -12,11 +12,11 @@ module SugarCRM; class Connection
12
12
 
13
13
  json = <<-EOF
14
14
  {
15
- \"session\": \"#{@session}\"\,
16
- \"search_string\": \"#{search_string}\"\,
17
- \"modules\": \"#{modules}\"\,
18
- \"offset\": #{options[:offset]}\,
19
- \"max_results\": #{options[:limit]}
15
+ "session": "#{@session}",
16
+ "search_string": "#{search_string}",
17
+ "modules": "#{modules}",
18
+ "offset": #{options[:offset]},
19
+ "max_results": #{options[:limit]}
20
20
  }
21
21
  EOF
22
22
  json.gsub!(/^\s{6}/,'')
@@ -4,9 +4,9 @@ module SugarCRM; class Connection
4
4
  login! unless logged_in?
5
5
  json = <<-EOF
6
6
  {
7
- \"session\": \"#{@session}\"\,
8
- \"targets\": #{targets.to_json}\,
9
- \"campaign-id\": \"#{campaign_id}\"
7
+ "session": "#{@session}",
8
+ "targets": #{targets.to_json},
9
+ "campaign-id": "#{campaign_id}"
10
10
  }
11
11
  EOF
12
12
  json.gsub!(/^\s{6}/,'')
@@ -4,9 +4,9 @@ module SugarCRM; class Connection
4
4
  login! unless logged_in?
5
5
  json = <<-EOF
6
6
  {
7
- \"session\": \"#{@session}\"\,
8
- \"document_revision\": \"#{revision}\"\,
9
- \"id\": #{id}
7
+ "session": "#{@session}",
8
+ "document_revision": "#{revision}",
9
+ "id": #{id}
10
10
  }
11
11
  EOF
12
12
  json.gsub!(/^\s{6}/,'')
@@ -4,9 +4,9 @@ module SugarCRM; class Connection
4
4
  login! unless logged_in?
5
5
  json = <<-EOF
6
6
  {
7
- \"session\": \"#{@session}\"\,
8
- \"module_name\": \"#{module_name}\"\,
9
- \"name_value_list\": #{name_value_lists.to_json}
7
+ "session": "#{@session}",
8
+ "module_name": "#{module_name}",
9
+ "name_value_list": #{name_value_lists.to_json}
10
10
  }
11
11
  EOF
12
12
  json.gsub!(/^\s{6}/,'')
@@ -4,9 +4,9 @@ module SugarCRM; class Connection
4
4
  login! unless logged_in?
5
5
  json = <<-EOF
6
6
  {
7
- \"session\": \"#{@session}\"\,
8
- \"module_name\": \"#{module_name}\"\,
9
- \"name_value_list\": #{name_value_list.to_json}
7
+ "session": "#{@session}",
8
+ "module_name": "#{module_name}",
9
+ "name_value_list": #{name_value_list.to_json}
10
10
  }
11
11
  EOF
12
12
  json.gsub!(/^\s{6}/,'')
@@ -1,3 +1,25 @@
1
1
  module SugarCRM; class Connection
2
- # to be implemented
3
- end; end
2
+ # Creates or updates an attachment on a note
3
+ def set_note_attachment(id, filename, file, opts={})
4
+ options = {
5
+ :module_id => '',
6
+ :module_name => ''
7
+ }.merge! opts
8
+
9
+ login! unless logged_in?
10
+ json = <<-EOF
11
+ {
12
+ "session": "#{@session}",
13
+ "note": {
14
+ "id": "#{id}",
15
+ "filename": "#{filename}",
16
+ "file": "#{Base64.encode64(file)}",
17
+ "related_module_id": "#{options[:module_id]}",
18
+ "related_module_name": "#{options[:module_name]}"
19
+ }
20
+ }
21
+ EOF
22
+ json.gsub!(/^\s{6}/,'')
23
+ send!(:set_note_attachment, json)
24
+ end
25
+ end; end
@@ -9,13 +9,13 @@ module SugarCRM; class Connection
9
9
  raise ArgumentError, "related_ids must be an Array" unless related_ids.class == Array
10
10
  json = <<-EOF
11
11
  {
12
- \"session\": \"#{@session}\"\,
13
- \"module_name\": \"#{module_name}\"\,
14
- \"module_id\": \"#{module_id}\"\,
15
- \"link_field_name\": \"#{link_field_name}\"\,
16
- \"related_ids\": #{related_ids.to_json}\,
17
- \"name_value_list\": #{options[:name_value_list].to_json}\,
18
- \"delete\": #{options[:delete]}
12
+ "session": "#{@session}",
13
+ "module_name": "#{module_name}",
14
+ "module_id": "#{module_id}",
15
+ "link_field_name": "#{link_field_name}",
16
+ "related_ids": #{related_ids.to_json},
17
+ "name_value_list": #{options[:name_value_list].to_json},
18
+ "delete": #{options[:delete]}
19
19
  }
20
20
  EOF
21
21
  json.gsub!(/^\s{6}/,'')
@@ -9,11 +9,11 @@ module SugarCRM; class Connection
9
9
 
10
10
  json = <<-EOF
11
11
  {
12
- \"session\": \"#{@session}\"\,
13
- \"module_names\": \"#{module_names.to_json}\"\,
14
- \"module_ids\": #{module_ids.to_json}\,
15
- \"link_field_names\": #{link_field_names.to_json}\,
16
- \"related_ids\": #{related_ids.to_json}
12
+ "session": "#{@session}",
13
+ "module_names": "#{module_names.to_json}",
14
+ "module_ids": #{module_ids.to_json},
15
+ "link_field_names": #{link_field_names.to_json},
16
+ "related_ids": #{related_ids.to_json}
17
17
  }
18
18
  EOF
19
19
  json.gsub!(/^\s{6}/,'')
@@ -29,7 +29,9 @@ module SugarCRM; class Connection
29
29
  resolve_url
30
30
  login!
31
31
  # make sure the environment singleton gets loaded
32
- SugarCRM::Environment.instance if @options[:load_environment]
32
+ if @options[:load_environment] # prevent loops when Environment tries to log in automatically
33
+ SugarCRM::Environment.update_config({:base_url => url, :username => user, :password => pass})
34
+ end
33
35
  self
34
36
  end
35
37
 
@@ -9,7 +9,7 @@ module SugarCRM; class Environment
9
9
  @config = {}
10
10
 
11
11
  # see README for reasoning behind the priorization
12
- ['/etc/sugarcrm.yaml', File.expand_path('~/.sugarcrm.yaml'), File.join(File.dirname(__FILE__), 'config', 'sugarcrm.yaml')].each{|path|
12
+ config_file_paths.each{|path|
13
13
  load_config path if File.exists? path
14
14
  }
15
15
  extensions_folder = File.join(File.dirname(__FILE__), 'extensions')
@@ -28,6 +28,14 @@ module SugarCRM; class Environment
28
28
  @config[k.to_sym] = v
29
29
  }
30
30
  end
31
+ @config
32
+ end
33
+
34
+ def update_config(params)
35
+ params.each{|k,v|
36
+ @config[k.to_sym] = v
37
+ }
38
+ @config
31
39
  end
32
40
 
33
41
  # load all the monkey patch extension files in the provided folder
@@ -42,6 +50,13 @@ module SugarCRM; class Environment
42
50
  end
43
51
 
44
52
  private
53
+ def config_file_paths
54
+ # see README for reasoning behind the priorization
55
+ paths = ['/etc/sugarcrm.yaml', File.expand_path('~/.sugarcrm.yaml'), File.join(File.dirname(__FILE__), 'config', 'sugarcrm.yaml')]
56
+ paths.insert(1, File.join(ENV['USERPROFILE'], 'sugarcrm.yaml')) if ENV['USERPROFILE']
57
+ paths
58
+ end
59
+
45
60
  def validate_path(path)
46
61
  raise "Invalid path: #{path}" unless File.exists? path
47
62
  end
@@ -18,7 +18,7 @@ class TestGetEntryList < Test::Unit::TestCase
18
18
  "Users",
19
19
  "users.deleted = 0"
20
20
  )
21
- assert_equal "Administrator", users.first.last_name
21
+ assert_equal "admin", users.first.user_name
22
22
  end
23
23
  should "return an object when #get_entry_list" do
24
24
  assert_instance_of Array, @response
@@ -0,0 +1,17 @@
1
+ require 'helper'
2
+
3
+ class TestSetNoteAttachment < Test::Unit::TestCase
4
+ context "A SugarCRM.connection" do
5
+ should "Add an attachment to a Note" do
6
+ SugarCRM.connect(URL, USER, PASS, {:debug => false})
7
+ n = SugarCRM::Note.new
8
+ n.name = "A Test Note"
9
+ assert n.save
10
+ file = File.read("test/config_test.yaml")
11
+ assert SugarCRM.connection.set_note_attachment(n.id, "config_test.yaml", file)
12
+ attachment = SugarCRM.connection.get_note_attachment(n.id)
13
+ assert Base64.decode64(attachment["file"]) == file
14
+ assert n.delete
15
+ end
16
+ end
17
+ end
data/test/helper.rb CHANGED
@@ -13,6 +13,6 @@ class Test::Unit::TestCase
13
13
  PASS = 'letmein'
14
14
 
15
15
  def setup_connection
16
- SugarCRM::Base.establish_connection(URL, USER, PASS, {:debug => false})
16
+ SugarCRM.connect(URL, USER, PASS, {:debug => false})
17
17
  end
18
18
  end
@@ -1,6 +1,13 @@
1
1
  require 'helper'
2
2
 
3
3
  class TestAssociations < Test::Unit::TestCase
4
+ context "A SugarCRM::Associations class" do
5
+ should "Return an array of Association objects when self#register(SugarCRM::User.new)" do
6
+ associations = SugarCRM::Associations.register(SugarCRM::User.new)
7
+ assert associations.include? "email_addresses"
8
+ assert associations.proxy_methods.include? "email_addresses"
9
+ end
10
+ end
4
11
  context "A SugarCRM::Base instance" do
5
12
  should "return an email address when sent #email_addresses" do
6
13
  u = SugarCRM::User.find("seed_sarah_id")
@@ -37,5 +44,96 @@ class TestAssociations < Test::Unit::TestCase
37
44
  a = SugarCRM::Account.first
38
45
  assert_instance_of SugarCRM::User, a.created_by_link.first
39
46
  end
47
+
48
+ should "create relationships with associate!" do
49
+ a = SugarCRM::Account.first
50
+ c = SugarCRM::Contact.create(:last_name => 'Doe')
51
+
52
+ nb_contacts = a.contacts.size
53
+ a.associate!(c)
54
+ assert_equal nb_contacts + 1, a.contacts.size # test association_cache is updated
55
+
56
+ assert_equal nb_contacts + 1, SugarCRM::Account.first.contacts.size # test relationship is created in Sugar
57
+
58
+ assert c.delete
59
+ end
60
+
61
+ should "destroy relationships with disassociate!" do
62
+ a = SugarCRM::Account.first
63
+ c = SugarCRM::Contact.create(:last_name => 'Doe')
64
+
65
+ a.associate!(c)
66
+ nb_contacts = a.contacts.size
67
+ a.disassociate!(c)
68
+ assert_equal nb_contacts - 1, a.contacts.size # test association_cache is updated
69
+
70
+ assert_equal nb_contacts - 1, SugarCRM::Account.first.contacts.size # test relationship is destroyed in Sugar
71
+
72
+ assert c.delete
73
+ end
74
+
75
+ should "not destroy a relationship if associate! is called with {:delete => 0}" do
76
+ a = SugarCRM::Account.first
77
+ c = SugarCRM::Contact.create(:last_name => 'Doe')
78
+
79
+ a.associate!(c)
80
+ nb_contacts = a.contacts.size
81
+ a.associate!(c, {:delete => 0})
82
+ assert_equal nb_contacts, a.contacts.size
83
+
84
+ assert c.delete
85
+ end
86
+
87
+ should "update association cache on associate! only if association changes" do
88
+ a = SugarCRM::Account.first
89
+ c = SugarCRM::Contact.create(:last_name => 'Doe')
90
+
91
+ nb_contacts = a.contacts.size
92
+ a.associate!(c)
93
+ assert_equal nb_contacts + 1, a.contacts.size
94
+ a.associate!(c)
95
+ assert_equal nb_contacts + 1, a.contacts.size # should not change: already associated
96
+
97
+ assert c.delete
98
+ end
99
+
100
+ should "update association cache on << only if association changes" do
101
+ a = SugarCRM::Account.first
102
+ c = SugarCRM::Contact.create(:last_name => 'Doe')
103
+
104
+ nb_contacts = a.contacts.size
105
+ a.contacts << c
106
+ assert_equal nb_contacts + 1, a.contacts.size
107
+ a.contacts << c
108
+ assert_equal nb_contacts + 1, a.contacts.size # should not change: already associated
109
+
110
+ assert c.delete
111
+ end
112
+
113
+ should "update association cache for both sides of the relationship when calling associate!" do
114
+ a = SugarCRM::Account.first
115
+ c = SugarCRM::Contact.create(:last_name => 'Doe')
116
+
117
+ nb_contacts = a.contacts.size
118
+ nb_accounts = c.accounts.size
119
+ a.associate!(c)
120
+ assert_equal nb_contacts + 1, a.contacts.size
121
+ assert_equal nb_accounts + 1, c.accounts.size
122
+
123
+ assert c.delete
124
+ end
125
+
126
+ should "update association cache for both sides of the relationship when calling <<" do
127
+ a = SugarCRM::Account.first
128
+ c = SugarCRM::Contact.create(:last_name => 'Doe')
129
+
130
+ nb_contacts = a.contacts.size
131
+ nb_accounts = c.accounts.size
132
+ a.contacts << c
133
+ assert_equal nb_contacts + 1, a.contacts.size
134
+ assert_equal nb_accounts + 1, c.accounts.size
135
+
136
+ assert c.delete
137
+ end
40
138
  end
41
139
  end
@@ -33,6 +33,13 @@ class TestEnvironment < Test::Unit::TestCase
33
33
  SugarCRM::Environment.load_config File.join(File.dirname(__FILE__), 'config_test.yaml')
34
34
  assert SugarCRM.connection.logged_in?
35
35
  end
36
+
37
+ should "update the login credentials on connection" do
38
+ SugarCRM.connect!(URL, USER, PASS)
39
+ {:base_url => URL, :username => USER, :password => PASS}.each{|k,v|
40
+ assert_equal v, SugarCRM::Environment.config[k]
41
+ }
42
+ end
36
43
  end
37
44
 
38
45
  end
@@ -182,58 +182,6 @@ class TestSugarCRM < Test::Unit::TestCase
182
182
  assert a.delete
183
183
  end
184
184
 
185
- should "update association cache on associate! only if association changes" do
186
- a = SugarCRM::Account.first
187
- c = SugarCRM::Contact.create(:last_name => 'Doe')
188
-
189
- nb_contacts = a.contacts.size
190
- a.associate!(c)
191
- assert_equal nb_contacts + 1, a.contacts.size
192
- a.associate!(c)
193
- assert_equal nb_contacts + 1, a.contacts.size # should not change: already associated
194
-
195
- c.delete
196
- end
197
-
198
- should "update association cache on << only if association changes" do
199
- a = SugarCRM::Account.first
200
- c = SugarCRM::Contact.create(:last_name => 'Doe')
201
-
202
- nb_contacts = a.contacts.size
203
- a.contacts << c
204
- assert_equal nb_contacts + 1, a.contacts.size
205
- a.contacts << c
206
- assert_equal nb_contacts + 1, a.contacts.size # should not change: already associated
207
-
208
- c.delete
209
- end
210
-
211
- should "update association cache for both sides of the relationship when calling associate!" do
212
- a = SugarCRM::Account.first
213
- c = SugarCRM::Contact.create(:last_name => 'Doe')
214
-
215
- nb_contacts = a.contacts.size
216
- nb_accounts = c.accounts.size
217
- a.associate!(c)
218
- assert_equal nb_contacts + 1, a.contacts.size
219
- assert_equal nb_accounts + 1, c.accounts.size
220
-
221
- c.delete
222
- end
223
-
224
- should "update association cache for both sides of the relationship when calling <<" do
225
- a = SugarCRM::Account.first
226
- c = SugarCRM::Contact.create(:last_name => 'Doe')
227
-
228
- nb_contacts = a.contacts.size
229
- nb_accounts = c.accounts.size
230
- a.contacts << c
231
- assert_equal nb_contacts + 1, a.contacts.size
232
- assert_equal nb_accounts + 1, c.accounts.size
233
-
234
- c.delete
235
- end
236
-
237
185
  should "support saving of records with special characters in them" do
238
186
  a = SugarCRM::Account.new
239
187
  a.name = "COHEN, WEISS & SIMON LLP"
metadata CHANGED
@@ -1,114 +1,108 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sugarcrm
3
3
  version: !ruby/object:Gem::Version
4
- hash: 41
5
4
  prerelease: false
6
5
  segments:
7
6
  - 0
8
7
  - 9
9
- - 9
10
- version: 0.9.9
8
+ - 10
9
+ version: 0.9.10
11
10
  platform: ruby
12
11
  authors:
13
12
  - Carl Hicks
13
+ - David Sulc
14
14
  autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-01-30 00:00:00 -08:00
18
+ date: 2011-02-06 00:00:00 -08:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
- type: :runtime
23
- prerelease: false
24
22
  name: activesupport
25
- version_requirements: &id001 !ruby/object:Gem::Requirement
23
+ requirement: &id001 !ruby/object:Gem::Requirement
26
24
  none: false
27
25
  requirements:
28
26
  - - ">="
29
27
  - !ruby/object:Gem::Version
30
- hash: 7
31
28
  segments:
32
29
  - 3
33
30
  - 0
34
31
  - 0
35
32
  version: 3.0.0
36
- requirement: *id001
37
- - !ruby/object:Gem::Dependency
38
33
  type: :runtime
39
34
  prerelease: false
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
40
37
  name: i18n
41
- version_requirements: &id002 !ruby/object:Gem::Requirement
38
+ requirement: &id002 !ruby/object:Gem::Requirement
42
39
  none: false
43
40
  requirements:
44
41
  - - ">="
45
42
  - !ruby/object:Gem::Version
46
- hash: 3
47
43
  segments:
48
44
  - 0
49
45
  version: "0"
50
- requirement: *id002
51
- - !ruby/object:Gem::Dependency
52
46
  type: :runtime
53
47
  prerelease: false
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
54
50
  name: json
55
- version_requirements: &id003 !ruby/object:Gem::Requirement
51
+ requirement: &id003 !ruby/object:Gem::Requirement
56
52
  none: false
57
53
  requirements:
58
54
  - - ">="
59
55
  - !ruby/object:Gem::Version
60
- hash: 3
61
56
  segments:
62
57
  - 0
63
58
  version: "0"
64
- requirement: *id003
65
- - !ruby/object:Gem::Dependency
66
- type: :development
59
+ type: :runtime
67
60
  prerelease: false
61
+ version_requirements: *id003
62
+ - !ruby/object:Gem::Dependency
68
63
  name: shoulda
69
- version_requirements: &id004 !ruby/object:Gem::Requirement
64
+ requirement: &id004 !ruby/object:Gem::Requirement
70
65
  none: false
71
66
  requirements:
72
67
  - - ">="
73
68
  - !ruby/object:Gem::Version
74
- hash: 3
75
69
  segments:
76
70
  - 0
77
71
  version: "0"
78
- requirement: *id004
79
- - !ruby/object:Gem::Dependency
80
72
  type: :development
81
73
  prerelease: false
74
+ version_requirements: *id004
75
+ - !ruby/object:Gem::Dependency
82
76
  name: bundler
83
- version_requirements: &id005 !ruby/object:Gem::Requirement
77
+ requirement: &id005 !ruby/object:Gem::Requirement
84
78
  none: false
85
79
  requirements:
86
80
  - - ~>
87
81
  - !ruby/object:Gem::Version
88
- hash: 23
89
82
  segments:
90
83
  - 1
91
84
  - 0
92
85
  - 0
93
86
  version: 1.0.0
94
- requirement: *id005
95
- - !ruby/object:Gem::Dependency
96
87
  type: :development
97
88
  prerelease: false
89
+ version_requirements: *id005
90
+ - !ruby/object:Gem::Dependency
98
91
  name: jeweler
99
- version_requirements: &id006 !ruby/object:Gem::Requirement
92
+ requirement: &id006 !ruby/object:Gem::Requirement
100
93
  none: false
101
94
  requirements:
102
95
  - - ~>
103
96
  - !ruby/object:Gem::Version
104
- hash: 7
105
97
  segments:
106
98
  - 1
107
99
  - 5
108
100
  - 2
109
101
  version: 1.5.2
110
- requirement: *id006
111
- description: A less clunky way to interact with SugarCRM via REST. Instead of SugarCRM.connection.get_entry("Users", "1") you could use SugarCRM::User.find(1). There is support for collections a la SugarCRM::User.find(1).email_addresses, or SugarCRM::Contact.first.meetings << new_meeting. ActiveRecord style finders are in place, with limited support for conditions and joins.
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: *id006
105
+ description:
112
106
  email: carl.hicks@gmail.com
113
107
  executables: []
114
108
 
@@ -185,10 +179,10 @@ files:
185
179
  - test/connection/test_get_user_team_id.rb
186
180
  - test/connection/test_login.rb
187
181
  - test/connection/test_logout.rb
182
+ - test/connection/test_set_note_attachment.rb
188
183
  - test/connection/test_set_relationship.rb
189
184
  - test/extensions_test/patch.rb
190
185
  - test/helper.rb
191
- - test/test_association.rb
192
186
  - test/test_association_collection.rb
193
187
  - test/test_associations.rb
194
188
  - test/test_connection.rb
@@ -210,7 +204,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
210
204
  requirements:
211
205
  - - ">="
212
206
  - !ruby/object:Gem::Version
213
- hash: 3
207
+ hash: 957398452548061165
214
208
  segments:
215
209
  - 0
216
210
  version: "0"
@@ -219,7 +213,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
219
213
  requirements:
220
214
  - - ">="
221
215
  - !ruby/object:Gem::Version
222
- hash: 3
223
216
  segments:
224
217
  - 0
225
218
  version: "0"
@@ -229,7 +222,7 @@ rubyforge_project:
229
222
  rubygems_version: 1.3.7
230
223
  signing_key:
231
224
  specification_version: 3
232
- summary: Ruby based REST client for SugarCRM
225
+ summary: A less clunky way to interact with SugarCRM via REST.
233
226
  test_files:
234
227
  - test/connection/test_get_available_modules.rb
235
228
  - test/connection/test_get_entries.rb
@@ -242,10 +235,10 @@ test_files:
242
235
  - test/connection/test_get_user_team_id.rb
243
236
  - test/connection/test_login.rb
244
237
  - test/connection/test_logout.rb
238
+ - test/connection/test_set_note_attachment.rb
245
239
  - test/connection/test_set_relationship.rb
246
240
  - test/extensions_test/patch.rb
247
241
  - test/helper.rb
248
- - test/test_association.rb
249
242
  - test/test_association_collection.rb
250
243
  - test/test_associations.rb
251
244
  - test/test_connection.rb
@@ -1,18 +0,0 @@
1
- #TODO: Figure out how to test this.
2
-
3
-
4
- # That code works, but what didn't work:
5
- # document.tasks.size
6
- # document.associate!(task)
7
- # document.tasks.size
8
- # This seems to be fixed in HEAD in my repo. I haven't pushed the changes to your repo, because I don't really see why commit https://github.com/davidsulc/sugarcrm/commit/228375348c9113324370afa0aca4120eb117d3e1 fixes the issue...
9
- # Also, I fixed this case
10
- # document.tasks.size
11
- # document.associate!(task)
12
- # document.tasks.size # => 1 (correct)
13
- # document.associate!(task)
14
- # document.tasks.size # => 2 (incorrect: should remain 1)
15
- # One thing we should look into is
16
- # document.associate!(task)
17
- # document.tasks.size # => 1
18
- # task.documents.size # => 0 (should be 1)