diff --git a/app/graphql/mutations/integration_items/fetch_tax_items.rb b/app/graphql/mutations/integration_items/fetch_tax_items.rb deleted file mode 100644 index f593c43667e..00000000000 --- a/app/graphql/mutations/integration_items/fetch_tax_items.rb +++ /dev/null @@ -1,29 +0,0 @@ -# frozen_string_literal: true - -module Mutations - module IntegrationItems - class FetchTaxItems < BaseMutation - include AuthenticableApiUser - include RequiredOrganization - - REQUIRED_PERMISSION = 'organization:integrations:update' - - graphql_name 'FetchIntegrationTaxItems' - description 'Fetch integration tax items' - - argument :integration_id, ID, required: true - - type Types::IntegrationItems::Object.collection_type, null: false - - def resolve(**args) - integration = current_organization.integrations.find_by(id: args[:integration_id]) - - ::Integrations::Aggregator::SyncService.call(integration:, options: {only_tax_items: true}) - - result = ::Integrations::Aggregator::TaxItemsService.call(integration:) - - result.success? ? result.tax_items : result_error(result) - end - end - end -end diff --git a/app/graphql/mutations/integrations/netsuite/create.rb b/app/graphql/mutations/integrations/netsuite/create.rb index 03b56edd8ce..59c09b72737 100644 --- a/app/graphql/mutations/integrations/netsuite/create.rb +++ b/app/graphql/mutations/integrations/netsuite/create.rb @@ -18,8 +18,7 @@ class Create < BaseMutation def resolve(**args) result = ::Integrations::Netsuite::CreateService - .new(context[:current_user]) - .call(**args.merge(organization_id: current_organization.id)) + .call(params: args.merge(organization_id: current_organization.id)) result.success? ? result.integration : result_error(result) end diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index cf98bdb2e14..e45c3664aeb 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -71,7 +71,6 @@ class MutationType < Types::BaseObject field :fetch_integration_accounts, mutation: Mutations::IntegrationItems::FetchAccounts field :fetch_integration_items, mutation: Mutations::IntegrationItems::FetchItems - field :fetch_integration_tax_items, mutation: Mutations::IntegrationItems::FetchTaxItems field :sync_crm_integration_invoice, mutation: Mutations::Integrations::SyncCrmInvoice field :sync_integration_credit_note, mutation: Mutations::Integrations::SyncCreditNote diff --git a/app/jobs/integrations/aggregator/fetch_tax_items_job.rb b/app/jobs/integrations/aggregator/fetch_tax_items_job.rb deleted file mode 100644 index b755512019f..00000000000 --- a/app/jobs/integrations/aggregator/fetch_tax_items_job.rb +++ /dev/null @@ -1,17 +0,0 @@ -# frozen_string_literal: true - -module Integrations - module Aggregator - class FetchTaxItemsJob < ApplicationJob - queue_as 'integrations' - - retry_on LagoHttpClient::HttpError, wait: :polynomially_longer, attempts: 3 - retry_on RequestLimitError, wait: :polynomially_longer, attempts: 10 - - def perform(integration:) - result = Integrations::Aggregator::TaxItemsService.call(integration:) - result.raise_if_error! - end - end - end -end diff --git a/app/jobs/integrations/aggregator/perform_sync_job.rb b/app/jobs/integrations/aggregator/perform_sync_job.rb index a4ab2821570..5fbe42b21d9 100644 --- a/app/jobs/integrations/aggregator/perform_sync_job.rb +++ b/app/jobs/integrations/aggregator/perform_sync_job.rb @@ -8,16 +8,13 @@ class PerformSyncJob < ApplicationJob retry_on LagoHttpClient::HttpError, wait: :polynomially_longer, attempts: 3 retry_on RequestLimitError, wait: :polynomially_longer, attempts: 10 - def perform(integration:, sync_tax_items: false) + def perform(integration:, sync_items: true) sync_result = Integrations::Aggregator::SyncService.call(integration:) sync_result.raise_if_error! - items_result = Integrations::Aggregator::ItemsService.call(integration:) - items_result.raise_if_error! - - if sync_tax_items - tax_items_result = Integrations::Aggregator::TaxItemsService.call(integration:) - tax_items_result.raise_if_error! + if sync_items + items_result = Integrations::Aggregator::ItemsService.call(integration:) + items_result.raise_if_error! end end end diff --git a/app/services/integrations/aggregator/sync_service.rb b/app/services/integrations/aggregator/sync_service.rb index abac3172a6c..fc79105a31b 100644 --- a/app/services/integrations/aggregator/sync_service.rb +++ b/app/services/integrations/aggregator/sync_service.rb @@ -26,11 +26,7 @@ def sync_list list = case integration.type when 'Integrations::NetsuiteIntegration' { - accounts: 'netsuite-accounts-sync', - items: 'netsuite-items-sync', - subsidiaries: 'netsuite-subsidiaries-sync', - contacts: 'netsuite-contacts-sync', - tax_items: 'netsuite-tax-items-sync' + subsidiaries: 'netsuite-subsidiaries-sync' } when 'Integrations::XeroIntegration' { @@ -41,7 +37,6 @@ def sync_list end return [list[:items]] if options[:only_items] - return [list[:tax_items]] if options[:only_tax_items] return [list[:accounts]] if options[:only_accounts] list.values diff --git a/app/services/integrations/aggregator/tax_items_service.rb b/app/services/integrations/aggregator/tax_items_service.rb deleted file mode 100644 index 9a607594f5a..00000000000 --- a/app/services/integrations/aggregator/tax_items_service.rb +++ /dev/null @@ -1,69 +0,0 @@ -# frozen_string_literal: true - -module Integrations - module Aggregator - class TaxItemsService < BaseService - LIMIT = 450 - MAX_SUBSEQUENT_REQUESTS = 15 - - def action_path - "v1/#{provider}/taxitems" - end - - def call - @cursor = '' - @items = [] - - ActiveRecord::Base.transaction do - integration.integration_items.where(item_type: :tax).destroy_all - - MAX_SUBSEQUENT_REQUESTS.times do |_i| - response = http_client.get(headers:, params:) - - handle_tax_items(response['records']) - @cursor = response['next_cursor'] - - break if cursor.blank? - end - end - result.tax_items = items - - result - end - - private - - attr_reader :cursor, :items - - def headers - { - 'Connection-Id' => integration.connection_id, - 'Authorization' => "Bearer #{secret_key}", - 'Provider-Config-Key' => provider_key - } - end - - def handle_tax_items(new_items) - new_items.each do |item| - integration_item = IntegrationItem.new( - integration:, - external_id: item['id'], - external_name: item['name'], - item_type: :tax - ) - - integration_item.save! - - @items << integration_item - end - end - - def params - { - limit: LIMIT, - cursor: - } - end - end - end -end diff --git a/app/services/integrations/netsuite/create_service.rb b/app/services/integrations/netsuite/create_service.rb index 48ae5af5fd9..0328f8ab0b5 100644 --- a/app/services/integrations/netsuite/create_service.rb +++ b/app/services/integrations/netsuite/create_service.rb @@ -3,8 +3,16 @@ module Integrations module Netsuite class CreateService < BaseService - def call(**args) - organization = Organization.find_by(id: args[:organization_id]) + attr_reader :params + + def initialize(params:) + @params = params + + super + end + + def call + organization = Organization.find_by(id: params[:organization_id]) unless organization.premium_integrations.include?('netsuite') return result.not_allowed_failure!(code: 'premium_integration_missing') @@ -12,29 +20,26 @@ def call(**args) integration = Integrations::NetsuiteIntegration.new( organization:, - name: args[:name], - code: args[:code], - client_id: args[:client_id], - client_secret: args[:client_secret], - account_id: args[:account_id], - token_id: args[:token_id], - token_secret: args[:token_secret], - connection_id: args[:connection_id], - script_endpoint_url: args[:script_endpoint_url], - 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]) + name: params[:name], + code: params[:code], + client_id: params[:client_id], + client_secret: params[:client_secret], + account_id: params[:account_id], + token_id: params[:token_id], + token_secret: params[:token_secret], + connection_id: params[:connection_id], + script_endpoint_url: params[:script_endpoint_url], + sync_credit_notes: ActiveModel::Type::Boolean.new.cast(params[:sync_credit_notes]), + sync_invoices: ActiveModel::Type::Boolean.new.cast(params[:sync_invoices]), + sync_payments: ActiveModel::Type::Boolean.new.cast(params[:sync_payments]), + sync_sales_orders: ActiveModel::Type::Boolean.new.cast(params[:sync_sales_orders]) ) integration.save! if integration.type == 'Integrations::NetsuiteIntegration' Integrations::Aggregator::SendRestletEndpointJob.perform_later(integration:) - Integrations::Aggregator::PerformSyncJob.set(wait: 2.seconds).perform_later( - integration:, - sync_tax_items: true - ) + Integrations::Aggregator::PerformSyncJob.set(wait: 2.seconds).perform_later(integration:, sync_items: false) end result.integration = integration diff --git a/app/services/integrations/netsuite/update_service.rb b/app/services/integrations/netsuite/update_service.rb index 1209ad161fa..fccbb21b0f8 100644 --- a/app/services/integrations/netsuite/update_service.rb +++ b/app/services/integrations/netsuite/update_service.rb @@ -31,10 +31,7 @@ def call if integration.type == 'Integrations::NetsuiteIntegration' && integration.script_endpoint_url != old_script_url Integrations::Aggregator::SendRestletEndpointJob.perform_later(integration:) - Integrations::Aggregator::PerformSyncJob.set(wait: 2.seconds).perform_later( - integration:, - sync_tax_items: true - ) + Integrations::Aggregator::PerformSyncJob.set(wait: 2.seconds).perform_later(integration:, sync_items: false) end result.integration = integration diff --git a/schema.graphql b/schema.graphql index 3415e394964..f85c27c28a1 100644 --- a/schema.graphql +++ b/schema.graphql @@ -3975,17 +3975,6 @@ input FetchIntegrationItemsInput { integrationId: ID! } -""" -Autogenerated input type of FetchIntegrationTaxItems -""" -input FetchIntegrationTaxItemsInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - integrationId: ID! -} - """ Autogenerated input type of FinalizeAllInvoices """ @@ -5145,16 +5134,6 @@ type Mutation { input: FetchIntegrationItemsInput! ): IntegrationItemCollection! - """ - Fetch integration tax items - """ - fetchIntegrationTaxItems( - """ - Parameters for FetchIntegrationTaxItems - """ - input: FetchIntegrationTaxItemsInput! - ): IntegrationItemCollection! - """ Finalize all draft invoices """ diff --git a/schema.json b/schema.json index 8ceec1202f7..04ec6b9d6f7 100644 --- a/schema.json +++ b/schema.json @@ -18830,45 +18830,6 @@ ], "enumValues": null }, - { - "kind": "INPUT_OBJECT", - "name": "FetchIntegrationTaxItemsInput", - "description": "Autogenerated input type of FetchIntegrationTaxItems", - "interfaces": null, - "possibleTypes": null, - "fields": null, - "inputFields": [ - { - "name": "clientMutationId", - "description": "A unique identifier for the client performing the mutation.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "integrationId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - } - ], - "enumValues": null - }, { "kind": "INPUT_OBJECT", "name": "FinalizeAllInvoicesInput", @@ -25485,39 +25446,6 @@ } ] }, - { - "name": "fetchIntegrationTaxItems", - "description": "Fetch integration tax items", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "IntegrationItemCollection", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "input", - "description": "Parameters for FetchIntegrationTaxItems", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FetchIntegrationTaxItemsInput", - "ofType": null - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - } - ] - }, { "name": "finalizeAllInvoices", "description": "Finalize all draft invoices", diff --git a/spec/graphql/mutations/integration_items/fetch_tax_items_spec.rb b/spec/graphql/mutations/integration_items/fetch_tax_items_spec.rb deleted file mode 100644 index 61e4423168b..00000000000 --- a/spec/graphql/mutations/integration_items/fetch_tax_items_spec.rb +++ /dev/null @@ -1,61 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Mutations::IntegrationItems::FetchTaxItems, type: :graphql do - let(:required_permission) { 'organization:integrations:update' } - let(:membership) { create(:membership) } - let(:organization) { membership.organization } - let(:integration) { create(:netsuite_integration, organization:) } - let(:integration_item) { create(:integration_item, integration:, item_type: :tax) } - let(:sync_service) { instance_double(Integrations::Aggregator::SyncService) } - - let(:items_response) do - File.read(Rails.root.join('spec/fixtures/integration_aggregator/tax_items_response.json')) - end - - let(:mutation) do - <<~GQL - mutation($input: FetchIntegrationTaxItemsInput!) { - fetchIntegrationTaxItems(input: $input) { - collection { externalName, externalId } - } - } - GQL - end - - before do - allow(Integrations::Aggregator::SyncService).to receive(:new).and_return(sync_service) - allow(sync_service).to receive(:call).and_return(true) - - stub_request(:get, 'https://api.nango.dev/v1/netsuite/taxitems?cursor=&limit=450') - .to_return(status: 200, body: items_response, headers: {}) - - integration_item - end - - it_behaves_like 'requires current user' - it_behaves_like 'requires current organization' - it_behaves_like 'requires permission', 'organization:integrations:update' - - it 'fetches the integration tax items' do - result = execute_graphql( - current_user: membership.user, - current_organization: organization, - permissions: required_permission, - query: mutation, - variables: { - input: {integrationId: integration.id} - } - ) - - result_data = result['data']['fetchIntegrationTaxItems'] - - invoice_ids = result_data['collection'].map { |value| value['externalId'] } - - aggregate_failures do - expect(invoice_ids).to eq(%w[-3557 -3879 -4692 -5307]) - expect(integration.integration_items.where(item_type: :tax).count).to eq(4) - end - end -end diff --git a/spec/jobs/integrations/aggregator/fetch_tax_items_job_spec.rb b/spec/jobs/integrations/aggregator/fetch_tax_items_job_spec.rb deleted file mode 100644 index 790866bf4b4..00000000000 --- a/spec/jobs/integrations/aggregator/fetch_tax_items_job_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Integrations::Aggregator::FetchTaxItemsJob, type: :job do - subject(:fetch_tax_items_job) { described_class } - - let(:tax_items_service) { instance_double(Integrations::Aggregator::TaxItemsService) } - let(:integration) { create(:netsuite_integration) } - let(:result) { BaseService::Result.new } - - before do - allow(Integrations::Aggregator::TaxItemsService).to receive(:new).and_return(tax_items_service) - allow(tax_items_service).to receive(:call).and_return(result) - end - - it 'calls the tax items service' do - described_class.perform_now(integration:) - - expect(Integrations::Aggregator::TaxItemsService).to have_received(:new) - expect(tax_items_service).to have_received(:call) - end -end diff --git a/spec/jobs/integrations/aggregator/perform_sync_job_spec.rb b/spec/jobs/integrations/aggregator/perform_sync_job_spec.rb index b84730c4b43..f8b58a2ea92 100644 --- a/spec/jobs/integrations/aggregator/perform_sync_job_spec.rb +++ b/spec/jobs/integrations/aggregator/perform_sync_job_spec.rb @@ -3,11 +3,10 @@ require 'rails_helper' RSpec.describe Integrations::Aggregator::PerformSyncJob, type: :job do - subject(:perform_sync_job) { described_class.perform_now(integration:, sync_tax_items:) } + subject(:perform_sync_job) { described_class.perform_now(integration:, sync_items:) } let(:sync_service) { instance_double(Integrations::Aggregator::SyncService) } let(:items_service) { instance_double(Integrations::Aggregator::ItemsService) } - let(:tax_items_service) { instance_double(Integrations::Aggregator::TaxItemsService) } let(:integration) { create(:netsuite_integration) } let(:result) { BaseService::Result.new } @@ -18,14 +17,11 @@ allow(Integrations::Aggregator::ItemsService).to receive(:new).and_return(items_service) allow(items_service).to receive(:call).and_return(result) - allow(Integrations::Aggregator::TaxItemsService).to receive(:new).and_return(tax_items_service) - allow(tax_items_service).to receive(:call).and_return(result) - perform_sync_job end - context 'when sync_tax_items is true' do - let(:sync_tax_items) { true } + context 'when sync_items is true' do + let(:sync_items) { true } it 'calls the aggregator sync service' do aggregate_failures do @@ -40,17 +36,10 @@ expect(items_service).to have_received(:call) end end - - it 'calls the aggregator tax items service' do - aggregate_failures do - expect(Integrations::Aggregator::TaxItemsService).to have_received(:new) - expect(tax_items_service).to have_received(:call) - end - end end - context 'when sync_tax_items is false' do - let(:sync_tax_items) { false } + context 'when sync_items is false' do + let(:sync_items) { false } it 'calls the aggregator sync service' do aggregate_failures do @@ -59,17 +48,10 @@ end end - it 'calls the aggregator items service' do - aggregate_failures do - expect(Integrations::Aggregator::ItemsService).to have_received(:new) - expect(items_service).to have_received(:call) - end - end - - it 'does not call the aggregator tax items service' do + it 'does not call the aggregator items service' do aggregate_failures do - expect(Integrations::Aggregator::TaxItemsService).not_to have_received(:new) - expect(tax_items_service).not_to have_received(:call) + expect(Integrations::Aggregator::ItemsService).not_to have_received(:new) + expect(items_service).not_to have_received(:call) end end end diff --git a/spec/services/integrations/aggregator/sync_service_spec.rb b/spec/services/integrations/aggregator/sync_service_spec.rb index d6d93f3a2eb..6e3c4bee4ec 100644 --- a/spec/services/integrations/aggregator/sync_service_spec.rb +++ b/spec/services/integrations/aggregator/sync_service_spec.rb @@ -12,11 +12,7 @@ let(:sync_endpoint) { 'https://api.nango.dev/sync/trigger' } let(:syncs_list) do %w[ - netsuite-accounts-sync - netsuite-items-sync netsuite-subsidiaries-sync - netsuite-contacts-sync - netsuite-tax-items-sync ] end @@ -37,18 +33,5 @@ expect(payload[:syncs]).to eq(syncs_list) end end - - context 'when only items should be synced' do - it 'successfully performs sync' do - described_class.new(integration:, options: {only_items: true}).call - - expect(LagoHttpClient::Client).to have_received(:new) - .with(sync_endpoint) - expect(lago_client).to have_received(:post_with_response) do |payload| - expect(payload[:provider_config_key]).to eq('netsuite-tba') - expect(payload[:syncs]).to eq(%w[netsuite-items-sync]) - end - end - end end end diff --git a/spec/services/integrations/aggregator/tax_items_service_spec.rb b/spec/services/integrations/aggregator/tax_items_service_spec.rb deleted file mode 100644 index 929e4981990..00000000000 --- a/spec/services/integrations/aggregator/tax_items_service_spec.rb +++ /dev/null @@ -1,55 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Integrations::Aggregator::TaxItemsService do - subject(:tax_items_service) { described_class.new(integration:) } - - let(:integration) { create(:netsuite_integration) } - - describe '.call' do - let(:lago_client) { instance_double(LagoHttpClient::Client) } - let(:tax_items_endpoint) { 'https://api.nango.dev/v1/netsuite/taxitems' } - let(:headers) do - { - 'Connection-Id' => integration.connection_id, - 'Authorization' => "Bearer #{ENV["NANGO_SECRET_KEY"]}", - 'Provider-Config-Key' => 'netsuite-tba' - } - end - let(:params) do - { - limit: 450, - cursor: '' - } - end - - let(:aggregator_response) do - path = Rails.root.join('spec/fixtures/integration_aggregator/tax_items_response.json') - JSON.parse(File.read(path)) - end - - before do - allow(LagoHttpClient::Client).to receive(:new) - .with(tax_items_endpoint) - .and_return(lago_client) - allow(lago_client).to receive(:get) - .with(headers:, params:) - .and_return(aggregator_response) - - IntegrationItem.destroy_all - end - - it 'successfully fetches tax items' do - result = tax_items_service.call - - aggregate_failures do - expect(LagoHttpClient::Client).to have_received(:new).with(tax_items_endpoint) - expect(lago_client).to have_received(:get) - expect(result.tax_items.pluck('external_id')).to eq(%w[-3557 -3879 -4692 -5307]) - expect(IntegrationItem.count).to eq(4) - expect(IntegrationItem.first.item_type).to eq('tax') - end - end - end -end diff --git a/spec/services/integrations/netsuite/create_service_spec.rb b/spec/services/integrations/netsuite/create_service_spec.rb index 710e83c79ce..62b29a7e410 100644 --- a/spec/services/integrations/netsuite/create_service_spec.rb +++ b/spec/services/integrations/netsuite/create_service_spec.rb @@ -3,12 +3,11 @@ require 'rails_helper' RSpec.describe Integrations::Netsuite::CreateService, type: :service do - let(:service) { described_class.new(membership.user) } let(:membership) { create(:membership) } let(:organization) { membership.organization } describe '#call' do - subject(:service_call) { service.call(**create_args) } + subject(:service_call) { described_class.call(params: create_args) } let(:name) { 'Netsuite 1' } let(:script_endpoint_url) { Faker::Internet.url } @@ -63,7 +62,6 @@ allow(Integrations::Aggregator::SendRestletEndpointJob).to receive(:perform_later) allow(Integrations::Aggregator::PerformSyncJob).to receive(:perform_later) allow(Integrations::Aggregator::FetchItemsJob).to receive(:perform_later) - allow(Integrations::Aggregator::FetchTaxItemsJob).to receive(:perform_later) end context 'without validation errors' do