Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(hubspot): Sync invoices #2720

Merged
merged 7 commits into from
Oct 23, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# frozen_string_literal: true

module Integrations
module Aggregator
module Invoices
module Crm
class CreateCustomerAssociationJob < ApplicationJob
queue_as 'integrations'

retry_on LagoHttpClient::HttpError, wait: :polynomially_longer, attempts: 10
retry_on RequestLimitError, wait: :polynomially_longer, attempts: 10

def perform(invoice:)
result = Integrations::Aggregator::Invoices::Crm::CreateCustomerAssociationService.call(invoice:)
result.raise_if_error!
end
end
end
end
end
end
27 changes: 27 additions & 0 deletions app/jobs/integrations/aggregator/invoices/crm/create_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# frozen_string_literal: true

module Integrations
module Aggregator
module Invoices
module Crm
class CreateJob < ApplicationJob
queue_as 'integrations'

retry_on LagoHttpClient::HttpError, wait: :polynomially_longer, attempts: 10
retry_on Integrations::Aggregator::BasePayload::Failure, wait: :polynomially_longer, attempts: 10
retry_on RequestLimitError, wait: :polynomially_longer, attempts: 10

def perform(invoice:)
result = Integrations::Aggregator::Invoices::Crm::CreateService.call(invoice:)

if result.success?
Integrations::Aggregator::Invoices::Crm::CreateCustomerAssociationJob.perform_later(invoice:)
end

result.raise_if_error!
end
end
end
end
end
end
22 changes: 22 additions & 0 deletions app/jobs/integrations/aggregator/invoices/crm/update_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# frozen_string_literal: true

module Integrations
module Aggregator
module Invoices
module Crm
class UpdateJob < ApplicationJob
queue_as 'integrations'

retry_on LagoHttpClient::HttpError, wait: :polynomially_longer, attempts: 10
retry_on Integrations::Aggregator::BasePayload::Failure, wait: :polynomially_longer, attempts: 10
retry_on RequestLimitError, wait: :polynomially_longer, attempts: 10

def perform(invoice:)
result = Integrations::Aggregator::Invoices::Crm::UpdateService.call(invoice:)
result.raise_if_error!
end
end
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ class SyncCustomObjectsAndPropertiesJob < ApplicationJob
queue_as 'integrations'

def perform(integration:)
Integrations::Hubspot::Invoices::DeployObjectJob.perform_later(integration:)
Integrations::Hubspot::Subscriptions::DeployObjectJob.perform_later(integration:)
Integrations::Hubspot::Companies::DeployPropertiesJob.perform_later(integration:)
Integrations::Hubspot::Contacts::DeployPropertiesJob.perform_later(integration:)
Integrations::Hubspot::Invoices::DeployObjectService.call(integration:)
Integrations::Hubspot::Subscriptions::DeployObjectService.call(integration:)
Integrations::Hubspot::Companies::DeployPropertiesService.call(integration:)
Integrations::Hubspot::Contacts::DeployPropertiesService.call(integration:)
end
end
end
Expand Down
8 changes: 8 additions & 0 deletions app/models/invoice.rb
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,14 @@ def should_sync_invoice?
finalized? && customer.integration_customers.accounting_kind.any? { |c| c.integration.sync_invoices }
end

def should_sync_crm_invoice?
finalized? && should_update_crm_invoice?
end

def should_update_crm_invoice?
customer.integration_customers.crm_kind.any? { |c| c.integration.sync_invoices }
end

def should_sync_sales_order?
finalized? &&
customer.integration_customers.accounting_kind.any? do |c|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def create_body
{
'properties' => {
'name' => customer.name,
'domain' => customer.url,
'domain' => clean_url(customer.url),
'lago_customer_id' => customer.id,
'lago_customer_external_id' => customer.external_id,
'lago_billing_email' => customer.email,
Expand All @@ -25,7 +25,7 @@ def update_body
'input' => {
'properties' => {
'name' => customer.name,
'domain' => customer.url,
'domain' => clean_url(customer.url),
'lago_customer_id' => customer.id,
'lago_customer_external_id' => customer.external_id,
'lago_billing_email' => customer.email,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ def customer_url

URI.join(url, "/customer/", customer.id).to_s
end

def clean_url(url)
url = "http://#{url}" unless /\Ahttps?:\/\//.match?(url)

uri = URI.parse(url.to_s)
uri.host
end
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def create_body
'lastname' => customer.lastname,
'phone' => customer.phone,
'company' => customer.legal_name,
'website' => customer.url,
'website' => clean_url(customer.url),
'lago_customer_id' => customer.id,
'lago_customer_external_id' => customer.external_id,
'lago_billing_email' => customer.email,
Expand All @@ -32,7 +32,7 @@ def update_body
'lastname' => customer.lastname,
'phone' => customer.phone,
'company' => customer.legal_name,
'website' => customer.url
'website' => clean_url(customer.url)
}
}
}
Expand Down
21 changes: 21 additions & 0 deletions app/services/integrations/aggregator/invoices/crm/base_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# frozen_string_literal: true

module Integrations
module Aggregator
module Invoices
module Crm
class BaseService < Integrations::Aggregator::Invoices::BaseService
private

def integration_customer
@integration_customer ||= customer&.integration_customers&.crm_kind&.first
end

def payload
Integrations::Aggregator::Invoices::Payloads::Factory.new_instance(integration_customer:, invoice:)
end
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# frozen_string_literal: true

module Integrations
module Aggregator
module Invoices
module Crm
class CreateCustomerAssociationService < BaseService
def action_path
"v1/#{provider}/association"
end

def call
return result if !integration || !integration.sync_invoices || !payload.integration_invoice

http_client.put_with_response(payload.customer_association_body, headers)

result
rescue LagoHttpClient::HttpError => e
raise RequestLimitError(e) if request_limit_error?(e)

code = code(e)
message = message(e)

deliver_error_webhook(customer:, code:, message:)

raise e
rescue Integrations::Aggregator::BasePayload::Failure => e
deliver_error_webhook(customer:, code: e.code, message: e.code.humanize)
end
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# frozen_string_literal: true

module Integrations
module Aggregator
module Invoices
module Crm
class CreateService < BaseService
def action_path
"v1/#{provider}/records"
end

def call
return result unless integration
return result unless integration.sync_invoices
return result unless invoice.finalized?

response = http_client.post_with_response(payload.create_body, headers)
body = JSON.parse(response.body)

result.external_id = body['id']
return result unless result.external_id

IntegrationResource.create!(
integration:,
external_id: result.external_id,
syncable_id: invoice.id,
syncable_type: 'Invoice',
resource_type: :invoice
)

result
rescue LagoHttpClient::HttpError => e
raise RequestLimitError(e) if request_limit_error?(e)

code = code(e)
message = message(e)

deliver_error_webhook(customer:, code:, message:)

result
end

def call_async
return result.not_found_failure!(resource: 'invoice') unless invoice

::Integrations::Aggregator::Invoices::Crm::CreateJob.perform_later(invoice:)

result.invoice_id = invoice.id
result
end
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# frozen_string_literal: true

module Integrations
module Aggregator
module Invoices
module Crm
class UpdateService < BaseService
def action_path
"v1/#{provider}/records"
end

def call
return result unless integration
return result unless integration.sync_invoices
return result unless integration_invoice

response = http_client.put_with_response(payload.update_body, headers)
body = JSON.parse(response.body)

result.external_id = body['id']
result
rescue LagoHttpClient::HttpError => e
raise RequestLimitError(e) if request_limit_error?(e)

code = code(e)
message = message(e)

deliver_error_webhook(customer:, code:, message:)

result
end

def call_async
return result.not_found_failure!(resource: 'invoice') unless invoice

::Integrations::Aggregator::Invoices::Crm::UpdateJob.perform_later(invoice:)

result.invoice_id = invoice.id
result
end

private

def integration_invoice
invoice.integration_resources.where(resource_type: 'invoice', syncable_type: 'Invoice').first
end
end
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ def self.new_instance(integration_customer:, invoice:, type: 'invoice')
Integrations::Aggregator::Invoices::Payloads::Xero.new(integration_customer:, invoice:)
when 'Integrations::AnrokIntegration'
Integrations::Aggregator::Invoices::Payloads::Anrok.new(integration_customer:, invoice:)
when 'Integrations::HubspotIntegration'
Integrations::Aggregator::Invoices::Payloads::Hubspot.new(integration_customer:, invoice:)
else
raise(NotImplementedError)
end
Expand Down
Loading