public async Task verify_we_can_update_a_regular_property() { var contact = await _contactCreationFixture.CreateTestContact(); var adapter = new HubspotAdapter(); var props = new HubSpotContactProperties(); props.Add("mobilephone", "0499888777"); props.Add("city", "Update City"); var response = await adapter.UpdateContactDetailsAsync(_contactCreationFixture.TestContactId, props, _logger, isTest : true); Assert.Equal(HttpStatusCode.OK, response.StatusCode); response = await adapter.RetrieveHubspotContactById(_contactCreationFixture.TestContactId, false, _logger, isTest : true); Assert.Equal(HttpStatusCode.OK, response.StatusCode); contact = response.Payload; Assert.Equal("Update City", contact.city); }
/// <summary> /// Convert a bunch of properties to the name-value structure required by the HubSpot 'create' API /// </summary> /// <param name="email"></param> /// <param name="firstname"></param> /// <param name="lastname"></param> /// <param name="preferredName"></param> /// <param name="primaryPhone"></param> /// <param name="streetAddress"></param> /// <param name="city"></param> /// <param name="state"></param> /// <param name="postcode"></param> /// <param name="leadStatus"></param> /// <returns></returns> internal static HubSpotContactProperties AssembleContactProperties( string email, string firstname, string lastname, string preferredName, string primaryPhone, string streetAddress1, string streetAddress2, string city, string state, string postcode, string leadStatus, bool installationRecordExists) { var newContactProperties = new HubSpotContactProperties(); // Need to sanitise the properties received here. if (new EmailAddressAttribute().IsValid(email)) { newContactProperties.Add("email", email); } else { // This should not occur, as it will be filtered out by the caller. return(null); } if (UserInputIsValid(firstname)) { newContactProperties.Add("firstname", firstname); } if (UserInputIsValid(lastname)) { newContactProperties.Add("lastname", lastname); } if (UserInputIsValid(preferredName)) { newContactProperties.Add("preferred_name", preferredName); } if (UserInputIsValid(primaryPhone)) { newContactProperties.Add("phone", primaryPhone); } if (UserInputIsValid(streetAddress1, false) || UserInputIsValid(streetAddress2, false)) { var comma = string.Empty; if (!string.IsNullOrEmpty(streetAddress1) && !string.IsNullOrEmpty(streetAddress2)) { comma = ", "; } var address = streetAddress1 + comma + streetAddress2; newContactProperties.Add("address", address); // Hubspot expects street, unit, apartment, etc to be concatenated. } if (UserInputIsValid(city)) { newContactProperties.Add("city", city); } if (UserInputIsValid(state)) { newContactProperties.Add("state", state); } if (UserInputIsValid(postcode)) { newContactProperties.Add("zip", postcode); } newContactProperties.Add("hs_lead_status", ResolveLeadStatus(leadStatus)); newContactProperties.Add("lifecyclestage", "lead"); // They are not just a subscriber newContactProperties.Add("installationrecordexists", installationRecordExists?"true":"false"); return(newContactProperties); }
/// <summary> /// Updates a HubSpot contact fields with the given contract status /// </summary> /// <param name="email"></param> /// <param name="status"></param> /// <param name="log"></param> /// <param name="isTest"></param> /// <returns></returns> /// <remarks>Make 'status' an enum that reflects the Sharepoint 'ContractStatus' field</remarks> public async Task <HubSpotContactResult> UpdateContractStatusAsync( string email, string status, ILogger log, bool isTest) { // Check that the appropriate Hubspot API key was correctly retrieved in the static constructor var activeHapiKey = isTest ? sandbox_hapikey : hapikey; if (string.IsNullOrEmpty(activeHapiKey)) { return(new HubSpotContactResult(HttpStatusCode.InternalServerError, "Hubspot API key not found")); } // To update a Contact Property we need a HubSpotContactProperties object that specifies all the properties var props = new HubSpotContactProperties(); var internalLeadStatusValue = string.Empty; // For now, we update a few fields: // 'Lead Status' - used by Brian for reporting. Not sustainable, will fall over when the a contact has two installations // I would like to retire these two states from Lead Status and re-do the reports. // // 'TotalSentContracts' // 'TotalSignedContracts' - these will support aggregates. But aggregates are expense to obtain from Sharepoint. When we // move the Installations table to SQL Server, we will revisit this logic and compute aggregates. // // So there is a temporary hack here right now. We're not computing proper totals. switch (status.ToLower()) { case "sent": props.Add("totalsentcontracts", "1"); internalLeadStatusValue = "CONTRACT_SENT"; break; case "signed": props.Add("totalsignedcontracts", "1"); internalLeadStatusValue = "CONTRACT_SIGNED"; break; case "rejected": props.Add("totalsignedcontracts", "0"); internalLeadStatusValue = "NOT_INTERESTED"; break; default: throw new CrmUpdateHandlerException("Unrecognised contract status: '" + status + "'"); } props.Add("hs_lead_status", internalLeadStatusValue); // We need to resolve the email into a contact id (a 'vid', in HubSpot language) var hubSpotContactResult = await this.RetrieveHubspotContactByEmailAddr(email, false, log, isTest); if (hubSpotContactResult.StatusCode != HttpStatusCode.OK) { log.LogInformation($"Error {hubSpotContactResult.StatusCode} retrieving HubSpot details for '{email}': {hubSpotContactResult.ErrorMessage}"); return(hubSpotContactResult); } // Great, we managed to retrieve the contact via the email address. var vid = hubSpotContactResult.Payload.contactId; // Now just POST it - see https://developers.hubspot.com/docs/methods/contacts/update_contact // Returns a 204 No Content on success var url = string.Format($"https://api.hubapi.com/contacts/v1/contact/vid/{vid}/profile?hapikey={activeHapiKey}"); log.LogInformation($"Updating {vid} contract status to {status}"); HttpResponseMessage response = await httpClient.PostAsJsonAsync(url, props); // Check Status Code. if (response.StatusCode == HttpStatusCode.NoContent) { log.LogInformation("Hubspot status update OK"); var retval = new HubSpotContactResult(HttpStatusCode.OK); return(retval); } else { // Some kind of error - return the status code and body to the caller of the function string resultText = await response.Content.ReadAsStringAsync(); log.LogError("Hubspot update failed: {0}: {1}", response.StatusCode, resultText); return(new HubSpotContactResult(response.StatusCode, string.Format($"Error {response.StatusCode}: '{resultText}'"))); } }