From 50fbe36fac1c66315bfc0a7abcfc5b9156888263 Mon Sep 17 00:00:00 2001 From: Brian Date: Mon, 23 Apr 2018 12:25:28 -0400 Subject: [PATCH 1/6] set Amount to a nullable Double to reflect that a deal in HubSpot does not require an amount --- HubSpot.NET/Api/Deal/Dto/DealHubSpotModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HubSpot.NET/Api/Deal/Dto/DealHubSpotModel.cs b/HubSpot.NET/Api/Deal/Dto/DealHubSpotModel.cs index 0713675e..4295ce18 100644 --- a/HubSpot.NET/Api/Deal/Dto/DealHubSpotModel.cs +++ b/HubSpot.NET/Api/Deal/Dto/DealHubSpotModel.cs @@ -53,7 +53,7 @@ public DealHubSpotModel() public string CloseDate { get; set; } [DataMember(Name = "amount")] - public double Amount { get; set; } + public double? Amount { get; set; } [DataMember(Name = "dealtype")] public string DealType { get; set; } From 9cb1509c7d79592bdd3ae87bcae373b733dd8966 Mon Sep 17 00:00:00 2001 From: Brian Date: Mon, 23 Apr 2018 12:26:49 -0400 Subject: [PATCH 2/6] resolves error with an empty amount --- .../Core/Requests/RequestDataConverter.cs | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/HubSpot.NET/Core/Requests/RequestDataConverter.cs b/HubSpot.NET/Core/Requests/RequestDataConverter.cs index cbf76343..87c453ea 100644 --- a/HubSpot.NET/Core/Requests/RequestDataConverter.cs +++ b/HubSpot.NET/Core/Requests/RequestDataConverter.cs @@ -219,12 +219,25 @@ internal object ConvertSingleEntity(ExpandoObject dynamicObject, object dto) if (targetProp != null) { - + var isNullable = false; + if (targetProp.PropertyType.Name.Contains("Nullable")) + { + isNullable = true; + } Type t = Nullable.GetUnderlyingType(targetProp.PropertyType) ?? targetProp.PropertyType; - var value = dynamicValue.GetType() == t ? dynamicValue : Convert.ChangeType(dynamicValue, t); - - targetProp.SetValue(dto, value); + // resolves bug where if the object property was a nullable number (int/double/etc.) and the value being processed + // was null or an empty string an exception 'string was not in the correct format' occurred. + if (isNullable && (dynamicValue == null || string.IsNullOrEmpty(dynamicValue.ToString()))) + { + // if nullable and the value to convert is null or an empty string it should not be converted + targetProp.SetValue(dto, null); + } + else + { + var value = dynamicValue.GetType() == t ? dynamicValue : Convert.ChangeType(dynamicValue, t); + targetProp.SetValue(dto, value); + } } } return dto; From 0988b05730d55acd8f0a3de19871488ac1d11809 Mon Sep 17 00:00:00 2001 From: Brian Date: Mon, 23 Apr 2018 12:28:59 -0400 Subject: [PATCH 3/6] added commented example to get all deals --- HubSpot.NET.Examples/Deals.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/HubSpot.NET.Examples/Deals.cs b/HubSpot.NET.Examples/Deals.cs index 3c355069..ff938084 100644 --- a/HubSpot.NET.Examples/Deals.cs +++ b/HubSpot.NET.Examples/Deals.cs @@ -33,6 +33,21 @@ public static void Example() */ var deals = api.Deal.List(false, new ListRequestOptions { PropertiesToInclude = new List { "dealname", "amount" } }); + + /** + * Get all deals + */ + //var moreResults = true; + //long offset = 0; + //while (moreResults) + //{ + // var allDeals = api.Deal.List(false, + // new ListRequestOptions { PropertiesToInclude = new List { "dealname", "amount", "hubspot_owner_id", "closedate" }, Limit = 100, Offset = offset }); + + // moreResults = allDeals.MoreResultsAvailable; + // if (moreResults) offset = allDeals.ContinuationOffset; + + //} } } } From e1aa702e4ea421b4863848dfaa8baa150a41cd96 Mon Sep 17 00:00:00 2001 From: Brian Date: Tue, 24 Apr 2018 15:54:01 -0400 Subject: [PATCH 4/6] added new list object that inherits from DealListHubSpotModel, added methods to retrieve recently modified/created deals --- .../Deal/Dto/DealRecentListHubSpotModel.cs | 27 +++++++ HubSpot.NET/Api/Deal/HubSpotDealApi.cs | 76 +++++++++++++++++++ .../Core/Interfaces/IHubSpotDealApi.cs | 6 ++ 3 files changed, 109 insertions(+) create mode 100644 HubSpot.NET/Api/Deal/Dto/DealRecentListHubSpotModel.cs diff --git a/HubSpot.NET/Api/Deal/Dto/DealRecentListHubSpotModel.cs b/HubSpot.NET/Api/Deal/Dto/DealRecentListHubSpotModel.cs new file mode 100644 index 00000000..4f8f711c --- /dev/null +++ b/HubSpot.NET/Api/Deal/Dto/DealRecentListHubSpotModel.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; +using HubSpot.NET.Api.Contact.Dto; +using HubSpot.NET.Core.Interfaces; + +namespace HubSpot.NET.Api.Deal.Dto +{ + /// + /// Models a set of results returned when querying for sets of deals + /// + /// + /// The sole reason for this class is because HubSpot returns the list for recently modified/created deals + /// in a 'results' property instead of the 'deals' property used when retrieving all deals. + /// + [DataContract] + public class DealRecentListHubSpotModel : DealListHubSpotModel, IHubSpotModel where T: DealHubSpotModel, new() + { + /// + /// Gets or sets the deals. + /// + /// + /// The deals. + /// + [DataMember(Name = "results")] + public new IList Deals { get; set; } = new List(); + } +} diff --git a/HubSpot.NET/Api/Deal/HubSpotDealApi.cs b/HubSpot.NET/Api/Deal/HubSpotDealApi.cs index ac3b04cf..37c7a65f 100644 --- a/HubSpot.NET/Api/Deal/HubSpotDealApi.cs +++ b/HubSpot.NET/Api/Deal/HubSpotDealApi.cs @@ -99,6 +99,80 @@ public HubSpotDealApi(IHubSpotClient client) return data; } + public DealRecentListHubSpotModel RecentlyCreatedList(bool includePropertyVersions, string since = "", ListRequestOptions opts = null) where T : DealHubSpotModel, new() + { + if (opts == null) + { + opts = new ListRequestOptions(); + } + + var path = $"{new DealRecentListHubSpotModel().RouteBasePath}/deal/recent/created" + .SetQueryParam("limit", opts.Limit); + + if (opts.Offset.HasValue) + { + path = path.SetQueryParam("offset", opts.Offset); + } + + // Recently created deals does not have an includeAssociations query parameter + // but does have 'includePropertyVersions and 'since' query parameters. + if (includePropertyVersions) + { + path = path.SetQueryParam("includePropertyVersions", "true"); + } + + if (!string.IsNullOrEmpty(since)) + { + path = path.SetQueryParam("since", since); + } + + if (opts.PropertiesToInclude.Any()) + { + path = path.SetQueryParam("properties", opts.PropertiesToInclude); + } + + var data = _client.ExecuteList>(path, opts); + + return data; + } + + public DealRecentListHubSpotModel RecentlyModifiedList(bool includePropertyVersions, string since = "", ListRequestOptions opts = null) where T : DealHubSpotModel, new() + { + if (opts == null) + { + opts = new ListRequestOptions(); + } + + var path = $"{new DealRecentListHubSpotModel().RouteBasePath}/deal/recent/modified" + .SetQueryParam("limit", opts.Limit); + + if (opts.Offset.HasValue) + { + path = path.SetQueryParam("offset", opts.Offset); + } + + // Recently created deals does not have an includeAssociations query parameter + // but does have 'includePropertyVersions and 'since' query parameters. + if (includePropertyVersions) + { + path = path.SetQueryParam("includePropertyVersions", "true"); + } + + if (!string.IsNullOrEmpty(since)) + { + path = path.SetQueryParam("since", since); + } + + if (opts.PropertiesToInclude.Any()) + { + path = path.SetQueryParam("properties", opts.PropertiesToInclude); + } + + var data = _client.ExecuteList>(path, opts); + + return data; + } + /// /// Deletes a given deal (by ID) /// @@ -109,5 +183,7 @@ public void Delete(long dealId) _client.Execute(path, method: Method.DELETE); } + + } } diff --git a/HubSpot.NET/Core/Interfaces/IHubSpotDealApi.cs b/HubSpot.NET/Core/Interfaces/IHubSpotDealApi.cs index 429beee5..b8f7f14a 100644 --- a/HubSpot.NET/Core/Interfaces/IHubSpotDealApi.cs +++ b/HubSpot.NET/Core/Interfaces/IHubSpotDealApi.cs @@ -12,5 +12,11 @@ public interface IHubSpotDealApi DealListHubSpotModel List(bool includeAssociations, ListRequestOptions opts = null) where T : DealHubSpotModel, new(); + + DealRecentListHubSpotModel RecentlyCreatedList(bool includePropertyVersions, string since = "", ListRequestOptions opts = null) + where T : DealHubSpotModel, new(); + + DealRecentListHubSpotModel RecentlyModifiedList(bool includePropertyVersions, string since = "", ListRequestOptions opts = null) + where T : DealHubSpotModel, new(); } } \ No newline at end of file From 9395b127613fb7f6206c3ae360c49afd99fa0fc0 Mon Sep 17 00:00:00 2001 From: Brian Futrell Date: Mon, 30 Apr 2018 15:24:16 -0400 Subject: [PATCH 5/6] Revert "added new list object that inherits from DealListHubSpotModel, added methods to retrieve recently modified/created deals" This reverts commit e1aa702e4ea421b4863848dfaa8baa150a41cd96. --- .../Deal/Dto/DealRecentListHubSpotModel.cs | 27 ------- HubSpot.NET/Api/Deal/HubSpotDealApi.cs | 76 ------------------- .../Core/Interfaces/IHubSpotDealApi.cs | 6 -- 3 files changed, 109 deletions(-) delete mode 100644 HubSpot.NET/Api/Deal/Dto/DealRecentListHubSpotModel.cs diff --git a/HubSpot.NET/Api/Deal/Dto/DealRecentListHubSpotModel.cs b/HubSpot.NET/Api/Deal/Dto/DealRecentListHubSpotModel.cs deleted file mode 100644 index 4f8f711c..00000000 --- a/HubSpot.NET/Api/Deal/Dto/DealRecentListHubSpotModel.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Collections.Generic; -using System.Runtime.Serialization; -using HubSpot.NET.Api.Contact.Dto; -using HubSpot.NET.Core.Interfaces; - -namespace HubSpot.NET.Api.Deal.Dto -{ - /// - /// Models a set of results returned when querying for sets of deals - /// - /// - /// The sole reason for this class is because HubSpot returns the list for recently modified/created deals - /// in a 'results' property instead of the 'deals' property used when retrieving all deals. - /// - [DataContract] - public class DealRecentListHubSpotModel : DealListHubSpotModel, IHubSpotModel where T: DealHubSpotModel, new() - { - /// - /// Gets or sets the deals. - /// - /// - /// The deals. - /// - [DataMember(Name = "results")] - public new IList Deals { get; set; } = new List(); - } -} diff --git a/HubSpot.NET/Api/Deal/HubSpotDealApi.cs b/HubSpot.NET/Api/Deal/HubSpotDealApi.cs index 37c7a65f..ac3b04cf 100644 --- a/HubSpot.NET/Api/Deal/HubSpotDealApi.cs +++ b/HubSpot.NET/Api/Deal/HubSpotDealApi.cs @@ -99,80 +99,6 @@ public HubSpotDealApi(IHubSpotClient client) return data; } - public DealRecentListHubSpotModel RecentlyCreatedList(bool includePropertyVersions, string since = "", ListRequestOptions opts = null) where T : DealHubSpotModel, new() - { - if (opts == null) - { - opts = new ListRequestOptions(); - } - - var path = $"{new DealRecentListHubSpotModel().RouteBasePath}/deal/recent/created" - .SetQueryParam("limit", opts.Limit); - - if (opts.Offset.HasValue) - { - path = path.SetQueryParam("offset", opts.Offset); - } - - // Recently created deals does not have an includeAssociations query parameter - // but does have 'includePropertyVersions and 'since' query parameters. - if (includePropertyVersions) - { - path = path.SetQueryParam("includePropertyVersions", "true"); - } - - if (!string.IsNullOrEmpty(since)) - { - path = path.SetQueryParam("since", since); - } - - if (opts.PropertiesToInclude.Any()) - { - path = path.SetQueryParam("properties", opts.PropertiesToInclude); - } - - var data = _client.ExecuteList>(path, opts); - - return data; - } - - public DealRecentListHubSpotModel RecentlyModifiedList(bool includePropertyVersions, string since = "", ListRequestOptions opts = null) where T : DealHubSpotModel, new() - { - if (opts == null) - { - opts = new ListRequestOptions(); - } - - var path = $"{new DealRecentListHubSpotModel().RouteBasePath}/deal/recent/modified" - .SetQueryParam("limit", opts.Limit); - - if (opts.Offset.HasValue) - { - path = path.SetQueryParam("offset", opts.Offset); - } - - // Recently created deals does not have an includeAssociations query parameter - // but does have 'includePropertyVersions and 'since' query parameters. - if (includePropertyVersions) - { - path = path.SetQueryParam("includePropertyVersions", "true"); - } - - if (!string.IsNullOrEmpty(since)) - { - path = path.SetQueryParam("since", since); - } - - if (opts.PropertiesToInclude.Any()) - { - path = path.SetQueryParam("properties", opts.PropertiesToInclude); - } - - var data = _client.ExecuteList>(path, opts); - - return data; - } - /// /// Deletes a given deal (by ID) /// @@ -183,7 +109,5 @@ public void Delete(long dealId) _client.Execute(path, method: Method.DELETE); } - - } } diff --git a/HubSpot.NET/Core/Interfaces/IHubSpotDealApi.cs b/HubSpot.NET/Core/Interfaces/IHubSpotDealApi.cs index b8f7f14a..429beee5 100644 --- a/HubSpot.NET/Core/Interfaces/IHubSpotDealApi.cs +++ b/HubSpot.NET/Core/Interfaces/IHubSpotDealApi.cs @@ -12,11 +12,5 @@ public interface IHubSpotDealApi DealListHubSpotModel List(bool includeAssociations, ListRequestOptions opts = null) where T : DealHubSpotModel, new(); - - DealRecentListHubSpotModel RecentlyCreatedList(bool includePropertyVersions, string since = "", ListRequestOptions opts = null) - where T : DealHubSpotModel, new(); - - DealRecentListHubSpotModel RecentlyModifiedList(bool includePropertyVersions, string since = "", ListRequestOptions opts = null) - where T : DealHubSpotModel, new(); } } \ No newline at end of file From 42d9ce2b46b8d0c4d2ce127aea9ea7cc537d2202 Mon Sep 17 00:00:00 2001 From: Dave Clarke Date: Tue, 1 May 2018 14:53:38 +0100 Subject: [PATCH 6/6] Add string extensions & combine bool check --- HubSpot.NET/Core/Extensions/StringExtensions.cs | 16 ++++++++++++++++ .../Core/Requests/RequestDataConverter.cs | 17 ++++++++--------- 2 files changed, 24 insertions(+), 9 deletions(-) create mode 100644 HubSpot.NET/Core/Extensions/StringExtensions.cs diff --git a/HubSpot.NET/Core/Extensions/StringExtensions.cs b/HubSpot.NET/Core/Extensions/StringExtensions.cs new file mode 100644 index 00000000..f159efb8 --- /dev/null +++ b/HubSpot.NET/Core/Extensions/StringExtensions.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HubSpot.NET.Core.Extensions +{ + public static class StringExtensions + { + public static bool IsNullOrEmpty(this string value) + { + return string.IsNullOrEmpty(value); + } + } +} diff --git a/HubSpot.NET/Core/Requests/RequestDataConverter.cs b/HubSpot.NET/Core/Requests/RequestDataConverter.cs index 87c453ea..2a505c3a 100644 --- a/HubSpot.NET/Core/Requests/RequestDataConverter.cs +++ b/HubSpot.NET/Core/Requests/RequestDataConverter.cs @@ -3,6 +3,7 @@ using System.Dynamic; using System.Linq; using System.Reflection; +using HubSpot.NET.Core.Extensions; using HubSpot.NET.Core.Interfaces; namespace HubSpot.NET.Core.Requests @@ -219,23 +220,21 @@ internal object ConvertSingleEntity(ExpandoObject dynamicObject, object dto) if (targetProp != null) { - var isNullable = false; - if (targetProp.PropertyType.Name.Contains("Nullable")) - { - isNullable = true; - } - Type t = Nullable.GetUnderlyingType(targetProp.PropertyType) ?? targetProp.PropertyType; + var isNullable = targetProp.PropertyType.Name.Contains("Nullable"); + + var type = Nullable.GetUnderlyingType(targetProp.PropertyType) ?? targetProp.PropertyType; - // resolves bug where if the object property was a nullable number (int/double/etc.) and the value being processed + // resolves issue where if the object property was a nullable number (int/double/etc.) and the value being processed // was null or an empty string an exception 'string was not in the correct format' occurred. - if (isNullable && (dynamicValue == null || string.IsNullOrEmpty(dynamicValue.ToString()))) + // see https://github.com/squaredup/HubSpot.NET/pull/8 + if (isNullable && (dynamicValue?.ToString()).IsNullOrEmpty()) { // if nullable and the value to convert is null or an empty string it should not be converted targetProp.SetValue(dto, null); } else { - var value = dynamicValue.GetType() == t ? dynamicValue : Convert.ChangeType(dynamicValue, t); + var value = dynamicValue.GetType() == type ? dynamicValue : Convert.ChangeType(dynamicValue, type); targetProp.SetValue(dto, value); } }