hubspot-api-ruby 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/Gemfile +3 -0
  4. data/Guardfile +9 -0
  5. data/LICENSE.txt +18 -0
  6. data/README.md +295 -0
  7. data/RELEASING.md +6 -0
  8. data/Rakefile +32 -0
  9. data/hubspot-api-ruby.gemspec +42 -0
  10. data/lib/hubspot-api-ruby.rb +39 -0
  11. data/lib/hubspot/blog.rb +98 -0
  12. data/lib/hubspot/collection.rb +41 -0
  13. data/lib/hubspot/company.rb +160 -0
  14. data/lib/hubspot/company_properties.rb +59 -0
  15. data/lib/hubspot/config.rb +63 -0
  16. data/lib/hubspot/connection.rb +152 -0
  17. data/lib/hubspot/contact.rb +110 -0
  18. data/lib/hubspot/contact_list.rb +129 -0
  19. data/lib/hubspot/contact_properties.rb +59 -0
  20. data/lib/hubspot/deal.rb +173 -0
  21. data/lib/hubspot/deal_pipeline.rb +58 -0
  22. data/lib/hubspot/deal_properties.rb +59 -0
  23. data/lib/hubspot/deprecator.rb +7 -0
  24. data/lib/hubspot/engagement.rb +222 -0
  25. data/lib/hubspot/event.rb +21 -0
  26. data/lib/hubspot/exceptions.rb +18 -0
  27. data/lib/hubspot/file.rb +38 -0
  28. data/lib/hubspot/form.rb +95 -0
  29. data/lib/hubspot/oauth.rb +50 -0
  30. data/lib/hubspot/owner.rb +57 -0
  31. data/lib/hubspot/paged_collection.rb +35 -0
  32. data/lib/hubspot/properties.rb +123 -0
  33. data/lib/hubspot/railtie.rb +10 -0
  34. data/lib/hubspot/resource.rb +270 -0
  35. data/lib/hubspot/subscription.rb +37 -0
  36. data/lib/hubspot/topic.rb +37 -0
  37. data/lib/hubspot/utils.rb +127 -0
  38. data/lib/tasks/hubspot.rake +53 -0
  39. data/spec/factories/companies.rb +9 -0
  40. data/spec/factories/contacts.rb +10 -0
  41. data/spec/lib/hubspot-ruby_spec.rb +12 -0
  42. data/spec/lib/hubspot/blog_spec.rb +150 -0
  43. data/spec/lib/hubspot/company_properties_spec.rb +410 -0
  44. data/spec/lib/hubspot/company_spec.rb +340 -0
  45. data/spec/lib/hubspot/config_spec.rb +87 -0
  46. data/spec/lib/hubspot/connection_spec.rb +214 -0
  47. data/spec/lib/hubspot/contact_list_spec.rb +301 -0
  48. data/spec/lib/hubspot/contact_properties_spec.rb +245 -0
  49. data/spec/lib/hubspot/contact_spec.rb +223 -0
  50. data/spec/lib/hubspot/deal_pipeline_spec.rb +85 -0
  51. data/spec/lib/hubspot/deal_properties_spec.rb +262 -0
  52. data/spec/lib/hubspot/deal_spec.rb +185 -0
  53. data/spec/lib/hubspot/deprecator_spec.rb +15 -0
  54. data/spec/lib/hubspot/engagement_spec.rb +177 -0
  55. data/spec/lib/hubspot/event_spec.rb +33 -0
  56. data/spec/lib/hubspot/file_spec.rb +38 -0
  57. data/spec/lib/hubspot/form_spec.rb +189 -0
  58. data/spec/lib/hubspot/owner_spec.rb +56 -0
  59. data/spec/lib/hubspot/properties_spec.rb +45 -0
  60. data/spec/lib/hubspot/resource_spec.rb +54 -0
  61. data/spec/lib/hubspot/topic_spec.rb +23 -0
  62. data/spec/lib/hubspot/utils_spec.rb +164 -0
  63. data/spec/lib/tasks/hubspot_spec.rb +119 -0
  64. data/spec/shared_examples/saveable_resource.rb +45 -0
  65. data/spec/shared_examples/updateable_resource.rb +87 -0
  66. data/spec/spec_helper.rb +44 -0
  67. data/spec/support/capture_output.rb +21 -0
  68. data/spec/support/cassette_helper.rb +19 -0
  69. data/spec/support/hubspot_api_helpers.rb +13 -0
  70. data/spec/support/rake.rb +46 -0
  71. data/spec/support/tests_helper.rb +17 -0
  72. data/spec/support/vcr.rb +16 -0
  73. metadata +369 -0
@@ -0,0 +1,110 @@
1
+ class Hubspot::Contact < Hubspot::Resource
2
+ self.id_field = "vid"
3
+ self.update_method = "post"
4
+
5
+ ALL_PATH = '/contacts/v1/lists/all/contacts/all'
6
+ CREATE_PATH = '/contacts/v1/contact'
7
+ CREATE_OR_UPDATE_PATH = '/contacts/v1/contact/createOrUpdate/email/:email'
8
+ DELETE_PATH = '/contacts/v1/contact/vid/:id'
9
+ FIND_PATH = '/contacts/v1/contact/vid/:id/profile'
10
+ FIND_BY_EMAIL_PATH = '/contacts/v1/contact/email/:email/profile'
11
+ FIND_BY_USER_TOKEN_PATH = '/contacts/v1/contact/utk/:token/profile'
12
+ MERGE_PATH = '/contacts/v1/contact/merge-vids/:id/'
13
+ SEARCH_PATH = '/contacts/v1/search/query'
14
+ UPDATE_PATH = '/contacts/v1/contact/vid/:id/profile'
15
+ UPDATE_PATH = '/contacts/v1/contact/vid/:id/profile'
16
+ BATCH_UPDATE_PATH = '/contacts/v1/contact/batch'
17
+
18
+ class << self
19
+ def all(opts = {})
20
+ Hubspot::PagedCollection.new(opts) do |options, offset, limit|
21
+ response = Hubspot::Connection.get_json(
22
+ ALL_PATH,
23
+ options.merge("count" => limit, "vidOffset" => offset)
24
+ )
25
+
26
+ contacts = response["contacts"].map { |result| from_result(result) }
27
+ [contacts, response["vid-offset"], response["has-more"]]
28
+ end
29
+ end
30
+
31
+ def find_by_email(email)
32
+ response = Hubspot::Connection.get_json(FIND_BY_EMAIL_PATH, email: email)
33
+ from_result(response)
34
+ end
35
+
36
+ def find_by_user_token(token)
37
+ response = Hubspot::Connection.get_json(FIND_BY_USER_TOKEN_PATH, token: token)
38
+ from_result(response)
39
+ end
40
+ alias_method :find_by_utk, :find_by_user_token
41
+
42
+ def create(email, properties = {})
43
+ super(properties.merge("email" => email))
44
+ end
45
+
46
+ def create_or_update(email, properties = {})
47
+ request = {
48
+ properties: Hubspot::Utils.hash_to_properties(properties.stringify_keys, key_name: "property")
49
+ }
50
+ response = Hubspot::Connection.post_json(CREATE_OR_UPDATE_PATH, params: {email: email}, body: request)
51
+ from_result(response)
52
+ end
53
+
54
+ def search(query, opts = {})
55
+ Hubspot::PagedCollection.new(opts) do |options, offset, limit|
56
+ response = Hubspot::Connection.get_json(
57
+ SEARCH_PATH,
58
+ options.merge(q: query, offset: offset, count: limit)
59
+ )
60
+
61
+ contacts = response["contacts"].map { |result| from_result(result) }
62
+ [contacts, response["offset"], response["has-more"]]
63
+ end
64
+ end
65
+
66
+ def merge(primary, secondary)
67
+ Hubspot::Connection.post_json(
68
+ MERGE_PATH,
69
+ params: { id: primary.to_i, no_parse: true },
70
+ body: { "vidToMerge" => secondary.to_i }
71
+ )
72
+
73
+ true
74
+ end
75
+
76
+ def batch_update(contacts, opts = {})
77
+ request = contacts.map do |contact|
78
+ # Use the specified options or update with the changes
79
+ changes = opts.empty? ? contact.changes : opts
80
+
81
+ unless changes.empty?
82
+ {
83
+ "vid" => contact.id,
84
+ "properties" => changes.map { |k, v| { "property" => k, "value" => v } }
85
+ }
86
+ end
87
+ end
88
+
89
+ # Remove any objects without changes and return if there is nothing to update
90
+ request.compact!
91
+ return true if request.empty?
92
+
93
+ Hubspot::Connection.post_json(
94
+ BATCH_UPDATE_PATH,
95
+ params: {},
96
+ body: request
97
+ )
98
+
99
+ true
100
+ end
101
+ end
102
+
103
+ def name
104
+ [firstname, lastname].compact.join(' ')
105
+ end
106
+
107
+ def merge(contact)
108
+ self.class.merge(@id, contact.to_i)
109
+ end
110
+ end
@@ -0,0 +1,129 @@
1
+ module Hubspot
2
+ #
3
+ # HubSpot Contact lists API
4
+ #
5
+ class ContactList
6
+ LISTS_PATH = '/contacts/v1/lists'
7
+ LIST_PATH = '/contacts/v1/lists/:list_id'
8
+ LIST_BATCH_PATH = LISTS_PATH + '/batch'
9
+ CONTACTS_PATH = LIST_PATH + '/contacts/all'
10
+ RECENT_CONTACTS_PATH = LIST_PATH + '/contacts/recent'
11
+ ADD_CONTACT_PATH = LIST_PATH + '/add'
12
+ REMOVE_CONTACT_PATH = LIST_PATH + '/remove'
13
+ REFRESH_PATH = LIST_PATH + '/refresh'
14
+
15
+ class << self
16
+ # {http://developers.hubspot.com/docs/methods/lists/create_list}
17
+ def create!(opts={})
18
+ dynamic = opts.delete(:dynamic) { false }
19
+ portal_id = opts.delete(:portal_id) { Hubspot::Config.portal_id }
20
+
21
+ response = Hubspot::Connection.post_json(LISTS_PATH, params: {}, body: opts.merge({ dynamic: dynamic, portal_id: portal_id}) )
22
+ new(response)
23
+ end
24
+
25
+ # {http://developers.hubspot.com/docs/methods/lists/get_lists}
26
+ # {http://developers.hubspot.com/docs/methods/lists/get_static_lists}
27
+ # {http://developers.hubspot.com/docs/methods/lists/get_dynamic_lists}
28
+ def all(opts={})
29
+ static = opts.delete(:static) { false }
30
+ dynamic = opts.delete(:dynamic) { false }
31
+
32
+ # NOTE: As opposed of what the documentation says, getting the static or dynamic lists returns all the lists, not only 20 lists
33
+ path = LISTS_PATH + (static ? '/static' : dynamic ? '/dynamic' : '')
34
+ response = Hubspot::Connection.get_json(path, opts)
35
+ response['lists'].map { |l| new(l) }
36
+ end
37
+
38
+ # {http://developers.hubspot.com/docs/methods/lists/get_list}
39
+ # {http://developers.hubspot.com/docs/methods/lists/get_batch_lists}
40
+ def find(ids)
41
+ batch_mode, path, params = case ids
42
+ when Integer then [false, LIST_PATH, { list_id: ids }]
43
+ when String then [false, LIST_PATH, { list_id: ids.to_i }]
44
+ when Array then [true, LIST_BATCH_PATH, { batch_list_id: ids.map(&:to_i) }]
45
+ else raise Hubspot::InvalidParams, 'expecting Integer or Array of Integers parameter'
46
+ end
47
+
48
+ response = Hubspot::Connection.get_json(path, params)
49
+ batch_mode ? response['lists'].map { |l| new(l) } : new(response)
50
+ end
51
+ end
52
+
53
+ attr_reader :id
54
+ attr_reader :portal_id
55
+ attr_reader :name
56
+ attr_reader :dynamic
57
+ attr_reader :properties
58
+
59
+ def initialize(hash)
60
+ self.send(:assign_properties, hash)
61
+ end
62
+
63
+ # {http://developers.hubspot.com/docs/methods/lists/update_list}
64
+ def update!(opts={})
65
+ response = Hubspot::Connection.post_json(LIST_PATH, params: { list_id: @id }, body: opts)
66
+ self.send(:assign_properties, response)
67
+ self
68
+ end
69
+
70
+ # {http://developers.hubspot.com/docs/methods/lists/delete_list}
71
+ def destroy!
72
+ response = Hubspot::Connection.delete_json(LIST_PATH, { list_id: @id })
73
+ @destroyed = (response.code == 204)
74
+ end
75
+
76
+ # {http://developers.hubspot.com/docs/methods/lists/get_list_contacts}
77
+ def contacts(opts={})
78
+ # NOTE: caching functionality can be dependant of the nature of the list, if dynamic or not ...
79
+ bypass_cache = opts.delete(:bypass_cache) { false }
80
+ recent = opts.delete(:recent) { false }
81
+ paged = opts.delete(:paged) { false }
82
+
83
+ if bypass_cache || @contacts.nil?
84
+ path = recent ? RECENT_CONTACTS_PATH : CONTACTS_PATH
85
+ opts[:list_id] = @id
86
+
87
+ response = Hubspot::Connection.get_json(path, Hubspot::ContactProperties.add_default_parameters(opts))
88
+ @contacts = response['contacts'].map! { |c| Hubspot::Contact.from_result(c) }
89
+ paged ? response : @contacts
90
+ else
91
+ @contacts
92
+ end
93
+ end
94
+
95
+ # {http://developers.hubspot.com/docs/methods/lists/refresh_list}
96
+ def refresh
97
+ response = Hubspot::Connection.post_json(REFRESH_PATH, params: { list_id: @id, no_parse: true }, body: {})
98
+ response.code == 204
99
+ end
100
+
101
+ # {http://developers.hubspot.com/docs/methods/lists/add_contact_to_list}
102
+ def add(contacts)
103
+ contact_ids = [contacts].flatten.uniq.compact.map(&:id)
104
+ response = Hubspot::Connection.post_json(ADD_CONTACT_PATH, params: { list_id: @id }, body: { vids: contact_ids })
105
+ response['updated'].sort == contact_ids.sort
106
+ end
107
+
108
+ # {http://developers.hubspot.com/docs/methods/lists/remove_contact_from_list}
109
+ def remove(contacts)
110
+ contact_ids = [contacts].flatten.uniq.compact.map(&:id)
111
+ response = Hubspot::Connection.post_json(REMOVE_CONTACT_PATH, params: { list_id: @id }, body: { vids: contact_ids })
112
+ response['updated'].sort == contact_ids.sort
113
+ end
114
+
115
+ def destroyed?
116
+ !!@destroyed
117
+ end
118
+
119
+ private
120
+
121
+ def assign_properties(hash)
122
+ @id = hash['listId']
123
+ @portal_id = hash['portalId']
124
+ @name = hash['name']
125
+ @dynamic = hash['dynamic']
126
+ @properties = hash
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,59 @@
1
+ module Hubspot
2
+ class ContactProperties < Properties
3
+
4
+ ALL_PROPERTIES_PATH = "/properties/v1/contacts/properties"
5
+ ALL_GROUPS_PATH = "/properties/v1/contacts/groups"
6
+ CREATE_PROPERTY_PATH = "/properties/v1/contacts/properties"
7
+ UPDATE_PROPERTY_PATH = "/properties/v1/contacts/properties/named/:property_name"
8
+ DELETE_PROPERTY_PATH = "/properties/v1/contacts/properties/named/:property_name"
9
+ CREATE_GROUP_PATH = "/properties/v1/contacts/groups"
10
+ UPDATE_GROUP_PATH = "/properties/v1/contacts/groups/named/:group_name"
11
+ DELETE_GROUP_PATH = "/properties/v1/contacts/groups/named/:group_name"
12
+
13
+ class << self
14
+ def add_default_parameters(opts={})
15
+ superclass.add_default_parameters(opts)
16
+ end
17
+
18
+ def all(opts={}, filter={})
19
+ superclass.all(ALL_PROPERTIES_PATH, opts, filter)
20
+ end
21
+
22
+ def groups(opts={}, filter={})
23
+ superclass.groups(ALL_GROUPS_PATH, opts, filter)
24
+ end
25
+
26
+ def create!(params={})
27
+ superclass.create!(CREATE_PROPERTY_PATH, params)
28
+ end
29
+
30
+ def update!(property_name, params={})
31
+ superclass.update!(UPDATE_PROPERTY_PATH, property_name, params)
32
+ end
33
+
34
+ def delete!(property_name)
35
+ superclass.delete!(DELETE_PROPERTY_PATH, property_name)
36
+ end
37
+
38
+ def create_group!(params={})
39
+ superclass.create_group!(CREATE_GROUP_PATH, params)
40
+ end
41
+
42
+ def update_group!(group_name, params={})
43
+ superclass.update_group!(UPDATE_GROUP_PATH, group_name, params)
44
+ end
45
+
46
+ def delete_group!(group_name)
47
+ superclass.delete_group!(DELETE_GROUP_PATH, group_name)
48
+ end
49
+
50
+ def same?(src, dst)
51
+ superclass.same?(src, dst)
52
+ end
53
+
54
+ def valid_params(params)
55
+ superclass.valid_params(params)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,173 @@
1
+ require 'hubspot/utils'
2
+
3
+ module Hubspot
4
+ #
5
+ # HubSpot Deals API
6
+ #
7
+ # {http://developers.hubspot.com/docs/methods/deals/deals_overview}
8
+ #
9
+ class Deal
10
+ ALL_DEALS_PATH = "/deals/v1/deal/paged"
11
+ CREATE_DEAL_PATH = "/deals/v1/deal"
12
+ DEAL_PATH = "/deals/v1/deal/:deal_id"
13
+ RECENT_UPDATED_PATH = "/deals/v1/deal/recent/modified"
14
+ UPDATE_DEAL_PATH = '/deals/v1/deal/:deal_id'
15
+ ASSOCIATE_DEAL_PATH = '/deals/v1/deal/:deal_id/associations/:OBJECTTYPE?id=:objectId'
16
+ ASSOCIATED_DEAL_PATH = "/deals/v1/deal/associated/:objectType/:objectId"
17
+
18
+ attr_reader :properties
19
+ attr_reader :portal_id
20
+ attr_reader :deal_id
21
+ attr_reader :company_ids
22
+ attr_reader :vids
23
+
24
+ def initialize(response_hash)
25
+ @portal_id = response_hash["portalId"]
26
+ @deal_id = response_hash["dealId"]
27
+ @company_ids = response_hash["associations"]["associatedCompanyIds"]
28
+ @vids = response_hash["associations"]["associatedVids"]
29
+ @properties = Hubspot::Utils.properties_to_hash(response_hash["properties"])
30
+ end
31
+
32
+ class << self
33
+ def create!(portal_id, company_ids, vids, params={})
34
+ #TODO: clean following hash, Hubspot::Utils should do the trick
35
+ associations_hash = {"portalId" => portal_id, "associations" => { "associatedCompanyIds" => company_ids, "associatedVids" => vids}}
36
+ post_data = associations_hash.merge({ properties: Hubspot::Utils.hash_to_properties(params, key_name: "name") })
37
+
38
+ response = Hubspot::Connection.post_json(CREATE_DEAL_PATH, params: {}, body: post_data )
39
+ new(response)
40
+ end
41
+
42
+ # Updates the properties of a deal
43
+ # {http://developers.hubspot.com/docs/methods/deals/update_deal}
44
+ # @param deal_id [Integer] hubspot deal_id
45
+ # @param params [Hash] hash of properties to update
46
+ # @return [boolean] success
47
+ def update(id, properties = {})
48
+ update!(id, properties)
49
+ rescue Hubspot::RequestError => e
50
+ false
51
+ end
52
+
53
+ # Updates the properties of a deal
54
+ # {http://developers.hubspot.com/docs/methods/deals/update_deal}
55
+ # @param deal_id [Integer] hubspot deal_id
56
+ # @param params [Hash] hash of properties to update
57
+ # @return [Hubspot::Deal] Deal record
58
+ def update!(id, properties = {})
59
+ request = { properties: Hubspot::Utils.hash_to_properties(properties.stringify_keys, key_name: 'name') }
60
+ response = Hubspot::Connection.put_json(UPDATE_DEAL_PATH, params: { deal_id: id, no_parse: true }, body: request)
61
+ response.success?
62
+ end
63
+
64
+ # Associate a deal with a contact or company
65
+ # {http://developers.hubspot.com/docs/methods/deals/associate_deal}
66
+ # Usage
67
+ # Hubspot::Deal.associate!(45146940, [], [52])
68
+ def associate!(deal_id, company_ids=[], vids=[])
69
+ objecttype = company_ids.any? ? 'COMPANY' : 'CONTACT'
70
+ object_ids = (company_ids.any? ? company_ids : vids).join('&id=')
71
+ Hubspot::Connection.put_json(ASSOCIATE_DEAL_PATH, params: { deal_id: deal_id, OBJECTTYPE: objecttype, objectId: object_ids}, body: {})
72
+ end
73
+
74
+ # Didssociate a deal with a contact or company
75
+ # {https://developers.hubspot.com/docs/methods/deals/delete_association}
76
+ # Usage
77
+ # Hubspot::Deal.dissociate!(45146940, [], [52])
78
+ def dissociate!(deal_id, company_ids=[], vids=[])
79
+ objecttype = company_ids.any? ? 'COMPANY' : 'CONTACT'
80
+ object_ids = (company_ids.any? ? company_ids : vids).join('&id=')
81
+ Hubspot::Connection.delete_json(ASSOCIATE_DEAL_PATH, { deal_id: deal_id, OBJECTTYPE: objecttype, objectId: object_ids })
82
+ end
83
+
84
+ def find(deal_id)
85
+ response = Hubspot::Connection.get_json(DEAL_PATH, { deal_id: deal_id })
86
+ new(response)
87
+ end
88
+
89
+ def all(opts = {})
90
+ path = ALL_DEALS_PATH
91
+
92
+ opts[:includeAssociations] = true # Needed for initialize to work
93
+ response = Hubspot::Connection.get_json(path, opts)
94
+
95
+ result = {}
96
+ result['deals'] = response['deals'].map { |d| new(d) }
97
+ result['offset'] = response['offset']
98
+ result['hasMore'] = response['hasMore']
99
+ return result
100
+ end
101
+
102
+ # Find recent updated deals.
103
+ # {http://developers.hubspot.com/docs/methods/deals/get_deals_modified}
104
+ # @param count [Integer] the amount of deals to return.
105
+ # @param offset [Integer] pages back through recent contacts.
106
+ def recent(opts = {})
107
+ response = Hubspot::Connection.get_json(RECENT_UPDATED_PATH, opts)
108
+ response['results'].map { |d| new(d) }
109
+ end
110
+
111
+ # Find all deals associated to a company
112
+ # {http://developers.hubspot.com/docs/methods/deals/get-associated-deals}
113
+ # @param company [Hubspot::Company] the company
114
+ # @return [Array] Array of Hubspot::Deal records
115
+ def find_by_company(company)
116
+ find_by_association company
117
+ end
118
+
119
+ # Find all deals associated to a contact
120
+ # {http://developers.hubspot.com/docs/methods/deals/get-associated-deals}
121
+ # @param contact [Hubspot::Contact] the contact
122
+ # @return [Array] Array of Hubspot::Deal records
123
+ def find_by_contact(contact)
124
+ find_by_association contact
125
+ end
126
+
127
+ # Find all deals associated to a contact or company
128
+ # {http://developers.hubspot.com/docs/methods/deals/get-associated-deals}
129
+ # @param object [Hubspot::Contact || Hubspot::Company] a contact or company
130
+ # @return [Array] Array of Hubspot::Deal records
131
+ def find_by_association(object)
132
+ path = ASSOCIATED_DEAL_PATH
133
+ objectType = case object
134
+ when Hubspot::Company then :company
135
+ when Hubspot::Contact then :contact
136
+ else raise(Hubspot::InvalidParams, "Instance type not supported")
137
+ end
138
+
139
+ params = { objectType: objectType, objectId: object.id }
140
+ response = Hubspot::Connection.get_json(path, params)
141
+ response["results"].map { |deal_id| find(deal_id) }
142
+ end
143
+ end
144
+
145
+ # Archives the contact in hubspot
146
+ # {https://developers.hubspot.com/docs/methods/contacts/delete_contact}
147
+ # @return [TrueClass] true
148
+ def destroy!
149
+ Hubspot::Connection.delete_json(DEAL_PATH, {deal_id: deal_id})
150
+ @destroyed = true
151
+ end
152
+
153
+ def destroyed?
154
+ !!@destroyed
155
+ end
156
+
157
+ def [](property)
158
+ @properties[property]
159
+ end
160
+
161
+ # Updates the properties of a deal
162
+ # {https://developers.hubspot.com/docs/methods/deals/update_deal}
163
+ # @param params [Hash] hash of properties to update
164
+ # @return [Hubspot::Deal] self
165
+ def update!(params)
166
+ query = { 'properties' => Hubspot::Utils.hash_to_properties(params.stringify_keys!, key_name: 'name') }
167
+ Hubspot::Connection.put_json(UPDATE_DEAL_PATH, params: { deal_id: deal_id }, body: query)
168
+ @properties.merge!(params)
169
+ self
170
+ end
171
+ alias_method :update, :update!
172
+ end
173
+ end