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

misc: add category to integration #2332

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open
2 changes: 1 addition & 1 deletion app/graphql/types/credit_notes/object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def integration_syncable
end

def external_integration_id
integration_customer = object.customer&.integration_customers&.accounting_kind&.first
integration_customer = object.customer&.accounting_customer

return nil unless integration_customer

Expand Down
9 changes: 1 addition & 8 deletions app/graphql/types/customers/object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,7 @@ def active_subscriptions_count
end

def provider_customer
case object&.payment_provider&.to_sym
when :stripe
object.stripe_customer
when :gocardless
object.gocardless_customer
when :adyen
object.adyen_customer
end
object&.payment_provider_customer
end

def credit_notes_credits_available_count
Expand Down
1 change: 1 addition & 0 deletions app/graphql/types/integrations/anrok.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class Anrok < Types::BaseObject
graphql_name 'AnrokIntegration'

field :api_key, String, null: false
field :category, String, null: true
field :code, String, null: false
field :external_account_id, String, null: true
field :has_mappings_configured, Boolean
Expand Down
1 change: 1 addition & 0 deletions app/graphql/types/integrations/netsuite.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class Netsuite < Types::BaseObject
graphql_name 'NetsuiteIntegration'

field :account_id, String, null: true
field :category, String, null: true
field :client_id, String, null: true
field :client_secret, String, null: true
field :code, String, null: false
Expand Down
1 change: 1 addition & 0 deletions app/graphql/types/integrations/okta.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module Integrations
class Okta < Types::BaseObject
graphql_name 'OktaIntegration'

field :category, String, null: true
field :client_id, String, null: true
field :client_secret, String, null: true
field :code, String, null: false
Expand Down
1 change: 1 addition & 0 deletions app/graphql/types/integrations/xero.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module Integrations
class Xero < Types::BaseObject
graphql_name 'XeroIntegration'

field :category, String, null: true
field :code, String, null: false
field :connection_id, ID, null: false
field :has_mappings_configured, Boolean
Expand Down
2 changes: 1 addition & 1 deletion app/graphql/types/invoices/object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def integration_syncable
end

def external_integration_id
integration_customer = object.customer&.integration_customers&.accounting_kind&.first
integration_customer = object.customer&.accounting_customer

return nil unless integration_customer

Expand Down
2 changes: 1 addition & 1 deletion app/models/credit_note.rb
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def add_on_items
end

def should_sync_credit_note?
finalized? && customer.integration_customers.accounting_kind.any? { |c| c.integration.sync_credit_notes }
finalized? & customer.accounting_customer&.integration&.sync_credit_notes
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated to bitwise and because logical and returns value if it exist instead of true/false
So in our case if second half returns nil,
&& - returns nil for the whole operation
& - returns false for the whole operation,
no matter what first argument was

end

def voidable?
Expand Down
24 changes: 13 additions & 11 deletions app/models/customer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,17 @@ class Customer < ApplicationRecord
has_one :anrok_customer, class_name: 'IntegrationCustomers::AnrokCustomer'
has_one :xero_customer, class_name: 'IntegrationCustomers::XeroCustomer'

# customer can have only one integration customer per integration_category
has_one :tax_provider_customer, -> {
includes(:integration).where(integration: {category: 'tax_provider'})
}, class_name: 'IntegrationCustomers::BaseCustomer'
has_one :accounting_customer, -> {
includes(:integration).where(integration: {category: 'accounting'})
}, class_name: 'IntegrationCustomers::BaseCustomer'

# customer can have only one payment_provider_customer
has_one :payment_provider_customer, class_name: 'PaymentProviderCustomers::BaseCustomer'

PAYMENT_PROVIDERS = %w[stripe gocardless adyen].freeze

default_scope -> { kept }
Expand All @@ -60,6 +71,8 @@ class Customer < ApplicationRecord
validates :payment_provider, inclusion: {in: PAYMENT_PROVIDERS}, allow_nil: true
validates :timezone, timezone: true, allow_nil: true

alias_method :provider_customer, :payment_provider_customer

def self.ransackable_attributes(_auth_object = nil)
%w[id name external_id email]
end
Expand Down Expand Up @@ -104,17 +117,6 @@ def preferred_document_locale
organization.document_locale.to_sym
end

def provider_customer
case payment_provider&.to_sym
when :stripe
stripe_customer
when :gocardless
gocardless_customer
when :adyen
adyen_customer
end
end

def shipping_address
{
address_line1: shipping_address_line1,
Expand Down
4 changes: 0 additions & 4 deletions app/models/integration_customers/base_customer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@ class BaseCustomer < ApplicationRecord

validates :customer_id, uniqueness: {scope: :type}

scope :accounting_kind, -> do
where(type: %w[IntegrationCustomers::NetsuiteCustomer IntegrationCustomers::XeroCustomer])
end

settings_accessors :sync_with_provider

def self.customer_type(type)
Expand Down
3 changes: 3 additions & 0 deletions app/models/integrations/base_integration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ class BaseIntegration < ApplicationRecord
validates :code, uniqueness: {scope: :organization_id}
validates :name, presence: true

INTEGRATION_CATEGORIES = %w[system accounting tax_provider]
enum category: INTEGRATION_CATEGORIES

def self.integration_type(type)
case type
when 'netsuite'
Expand Down
7 changes: 2 additions & 5 deletions app/models/invoice.rb
Original file line number Diff line number Diff line change
Expand Up @@ -287,14 +287,11 @@ def mark_as_dispute_lost!(timestamp = Time.current)
end

def should_sync_invoice?
finalized? && customer.integration_customers.accounting_kind.any? { |c| c.integration.sync_invoices }
finalized? & customer.accounting_customer&.integration&.sync_invoices
end

def should_sync_sales_order?
finalized? &&
customer.integration_customers.accounting_kind.any? do |c|
c.integration.respond_to?(:sync_sales_orders) && c.integration.sync_sales_orders
end
finalized? & customer.accounting_customer&.integration&.sync_sales_orders
end

private
Expand Down
2 changes: 1 addition & 1 deletion app/models/payment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ class Payment < ApplicationRecord
delegate :customer, to: :invoice

def should_sync_payment?
invoice.finalized? && customer.integration_customers.accounting_kind.any? { |c| c.integration.sync_payments }
invoice.finalized? & customer.accounting_customer&.integration&.sync_payments
end
end
16 changes: 4 additions & 12 deletions app/serializers/v1/customer_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,19 +59,11 @@ def billing_configuration
document_locale: model.document_locale
}

case model.payment_provider&.to_sym
when :stripe
configuration[:provider_customer_id] = model.stripe_customer&.provider_customer_id
configuration[:provider_payment_methods] = model.stripe_customer&.provider_payment_methods
configuration.merge!(model.stripe_customer&.settings || {})
when :gocardless
configuration[:provider_customer_id] = model.gocardless_customer&.provider_customer_id
configuration.merge!(model.gocardless_customer&.settings || {})
when :adyen
configuration[:provider_customer_id] = model.adyen_customer&.provider_customer_id
configuration.merge!(model.adyen_customer&.settings || {})
configuration[:provider_customer_id] = model.payment_provider_customer&.provider_customer_id
configuration.merge!(model.payment_provider_customer&.settings || {})
if model.payment_provider&.to_sym == :stripe
configuration[:provider_payment_methods] = model.payment_provider_customer&.provider_payment_methods
end

configuration
end

Expand Down
15 changes: 3 additions & 12 deletions app/services/customers/update_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -172,25 +172,16 @@ def assign_premium_attributes(customer, args)
def create_or_update_provider_customer(customer, payment_provider, billing_configuration = {})
handle_provider_customer = customer.payment_provider.present?
handle_provider_customer ||= (billing_configuration || {})[:provider_customer_id].present?
handle_provider_customer ||= customer.payment_provider_customer&.provider_customer_id.present?

return unless handle_provider_customer

case payment_provider
when 'stripe'
handle_provider_customer ||= customer.stripe_customer&.provider_customer_id.present?

return unless handle_provider_customer

update_stripe_customer(customer, billing_configuration)
when 'gocardless'
handle_provider_customer ||= customer.gocardless_customer&.provider_customer_id.present?

return unless handle_provider_customer

update_gocardless_customer(customer, billing_configuration)
when 'adyen'
handle_provider_customer ||= customer.adyen_customer&.provider_customer_id.present?

return unless handle_provider_customer

update_adyen_customer(customer, billing_configuration)
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def integration
end

def integration_customer
@integration_customer ||= customer&.integration_customers&.accounting_kind&.first
@integration_customer ||= customer&.accounting_customer
end

def payload(type)
Expand Down
3 changes: 2 additions & 1 deletion app/services/integrations/anrok/create_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ def call(**args)
name: args[:name],
code: args[:code],
connection_id: args[:connection_id],
api_key: args[:api_key]
api_key: args[:api_key],
category: 'tax_provider'
)

integration.save!
Expand Down
3 changes: 2 additions & 1 deletion app/services/integrations/netsuite/create_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ def call(**args)
sync_credit_notes: ActiveModel::Type::Boolean.new.cast(args[:sync_credit_notes]),
sync_invoices: ActiveModel::Type::Boolean.new.cast(args[:sync_invoices]),
sync_payments: ActiveModel::Type::Boolean.new.cast(args[:sync_payments]),
sync_sales_orders: ActiveModel::Type::Boolean.new.cast(args[:sync_sales_orders])
sync_sales_orders: ActiveModel::Type::Boolean.new.cast(args[:sync_sales_orders]),
category: 'accounting'
)

integration.save!
Expand Down
3 changes: 2 additions & 1 deletion app/services/integrations/okta/create_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ def call(**args)
client_id: args[:client_id],
client_secret: args[:client_secret],
domain: args[:domain],
organization_name: args[:organization_name]
organization_name: args[:organization_name],
category: 'system'
)

integration.save!
Expand Down
3 changes: 2 additions & 1 deletion app/services/integrations/xero/create_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ def call(**args)
connection_id: args[:connection_id],
sync_credit_notes: ActiveModel::Type::Boolean.new.cast(args[:sync_credit_notes]),
sync_invoices: ActiveModel::Type::Boolean.new.cast(args[:sync_invoices]),
sync_payments: ActiveModel::Type::Boolean.new.cast(args[:sync_payments])
sync_payments: ActiveModel::Type::Boolean.new.cast(args[:sync_payments]),
category: 'accounting'
)

integration.save!
Expand Down
2 changes: 1 addition & 1 deletion app/services/invoices/compute_amounts_from_fees.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def call
attr_reader :invoice, :provider_taxes

def customer_provider_taxation?
@customer_provider_taxation ||= invoice.customer.anrok_customer
@customer_provider_taxation ||= invoice.customer.tax_provider_customer
end

def fee_taxes(fee)
Expand Down
38 changes: 38 additions & 0 deletions db/migrate/20240724154417_add_category_to_integrations.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# frozen_string_literal: true

class AddCategoryToIntegrations < ActiveRecord::Migration[7.1]
module Integrations
class BaseIntegration < ApplicationRecord
self.table_name = 'integrations'
INTEGRATION_CATEGORIES = %w[system accounting tax_provider]
enum category: INTEGRATION_CATEGORIES
end

class AnrokIntegration < BaseIntegration
end

class NetsuiteIntegration < BaseIntegration
end

class XeroIntegration < BaseIntegration
end

class OktaIntegration < BaseIntegration
end
end

def up
add_column :integrations, :category, :integer
add_index :integrations, :category

Integrations::AnrokIntegration.update_all(category: 'tax_provider') # rubocop:disable Rails/SkipsModelValidations
Integrations::NetsuiteIntegration.update_all(category: 'accounting') # rubocop:disable Rails/SkipsModelValidations
Integrations::XeroIntegration.update_all(category: 'accounting') # rubocop:disable Rails/SkipsModelValidations
Integrations::OktaIntegration.update_all(category: 'system') # rubocop:disable Rails/SkipsModelValidations
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Run it locally on 4000 integrations - took 0.04s

end

def down
remove_index :integrations, :category
remove_column :integrations, :category
end
end
4 changes: 3 additions & 1 deletion db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions schema.graphql

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading