hubspot-api-ruby 0.8.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.
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