diff --git a/app/graphql/types/invoices/object.rb b/app/graphql/types/invoices/object.rb index e5e6465572c5..e9aee985dd9a 100644 --- a/app/graphql/types/invoices/object.rb +++ b/app/graphql/types/invoices/object.rb @@ -19,6 +19,7 @@ class Object < Types::BaseObject field :payment_dispute_lost_at, GraphQL::Types::ISO8601DateTime field :payment_status, Types::Invoices::PaymentStatusTypeEnum, null: false field :status, Types::Invoices::StatusTypeEnum, null: false + field :tax_status, Types::Invoices::TaxStatusTypeEnum, null: true field :voidable, Boolean, null: false, method: :voidable? field :currency, Types::CurrencyEnum diff --git a/app/graphql/types/invoices/tax_status_type_enum.rb b/app/graphql/types/invoices/tax_status_type_enum.rb new file mode 100644 index 000000000000..dc37aa999ec8 --- /dev/null +++ b/app/graphql/types/invoices/tax_status_type_enum.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Types + module Invoices + class TaxStatusTypeEnum < Types::BaseEnum + graphql_name 'InvoiceTaxStatusTypeEnum' + + Invoice::TAX_STATUSES.keys.each do |type| + value type + end + end + end +end diff --git a/app/jobs/fees/create_pay_in_advance_job.rb b/app/jobs/fees/create_pay_in_advance_job.rb index 3424c2380a7d..0a4c0285c923 100644 --- a/app/jobs/fees/create_pay_in_advance_job.rb +++ b/app/jobs/fees/create_pay_in_advance_job.rb @@ -2,8 +2,12 @@ module Fees class CreatePayInAdvanceJob < ApplicationJob + include ConcurrencyThrottlable + queue_as :default + retry_on BaseService::ThrottlingError, wait: :polynomially_longer, attempts: 25 + unique :until_executed, on_conflict: :log def perform(charge:, event:, billing_at: nil) diff --git a/app/jobs/invoices/create_pay_in_advance_charge_job.rb b/app/jobs/invoices/create_pay_in_advance_charge_job.rb index ac2b01521a29..1d56b70a3840 100644 --- a/app/jobs/invoices/create_pay_in_advance_charge_job.rb +++ b/app/jobs/invoices/create_pay_in_advance_charge_job.rb @@ -2,6 +2,8 @@ module Invoices class CreatePayInAdvanceChargeJob < ApplicationJob + include ConcurrencyThrottlable + queue_as do if ActiveModel::Type::Boolean.new.cast(ENV['SIDEKIQ_BILLING']) :billing @@ -11,6 +13,7 @@ class CreatePayInAdvanceChargeJob < ApplicationJob end retry_on Sequenced::SequenceError + retry_on BaseService::ThrottlingError, wait: :polynomially_longer, attempts: 25 unique :until_executed, on_conflict: :log diff --git a/app/jobs/invoices/provider_taxes/pull_taxes_and_apply_job.rb b/app/jobs/invoices/provider_taxes/pull_taxes_and_apply_job.rb index 0153240fdc15..18f9a8ca2457 100644 --- a/app/jobs/invoices/provider_taxes/pull_taxes_and_apply_job.rb +++ b/app/jobs/invoices/provider_taxes/pull_taxes_and_apply_job.rb @@ -3,8 +3,12 @@ module Invoices module ProviderTaxes class PullTaxesAndApplyJob < ApplicationJob + include ConcurrencyThrottlable + queue_as 'integrations' + retry_on BaseService::ThrottlingError, wait: :polynomially_longer, attempts: 25 + def perform(invoice:) Invoices::ProviderTaxes::PullTaxesAndApplyService.call(invoice:) end diff --git a/app/services/integrations/aggregator/taxes/invoices/create_draft_service.rb b/app/services/integrations/aggregator/taxes/invoices/create_draft_service.rb index 6d7b924d5a79..05204808399e 100644 --- a/app/services/integrations/aggregator/taxes/invoices/create_draft_service.rb +++ b/app/services/integrations/aggregator/taxes/invoices/create_draft_service.rb @@ -13,6 +13,8 @@ def call return result unless integration return result unless integration.type == 'Integrations::AnrokIntegration' + throttle!(:anrok) + response = http_client.post_with_response(payload, headers) body = JSON.parse(response.body) diff --git a/app/services/integrations/aggregator/taxes/invoices/create_service.rb b/app/services/integrations/aggregator/taxes/invoices/create_service.rb index 0f5318821073..202d820366a3 100644 --- a/app/services/integrations/aggregator/taxes/invoices/create_service.rb +++ b/app/services/integrations/aggregator/taxes/invoices/create_service.rb @@ -13,6 +13,8 @@ def call return result unless integration return result unless integration.type == 'Integrations::AnrokIntegration' + throttle!(:anrok) + response = http_client.post_with_response(payload, headers) body = JSON.parse(response.body) diff --git a/schema.graphql b/schema.graphql index 7332191b2698..1774b9b191ef 100644 --- a/schema.graphql +++ b/schema.graphql @@ -4475,6 +4475,7 @@ type Invoice { subTotalIncludingTaxesAmountCents: BigInt! subscriptions: [Subscription!] taxProviderVoidable: Boolean! + taxStatus: InvoiceTaxStatusTypeEnum taxesAmountCents: BigInt! taxesRate: Float! totalAmountCents: BigInt! @@ -4621,6 +4622,12 @@ type InvoiceSubscription { totalAmountCents: BigInt! } +enum InvoiceTaxStatusTypeEnum { + failed + pending + succeeded +} + enum InvoiceTypeEnum { add_on advance_charges diff --git a/schema.json b/schema.json index c78950548400..43fe17fd48be 100644 --- a/schema.json +++ b/schema.json @@ -21064,6 +21064,18 @@ "deprecationReason": null, "args": [] }, + { + "name": "taxStatus", + "description": null, + "type": { + "kind": "ENUM", + "name": "InvoiceTaxStatusTypeEnum", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null, + "args": [] + }, { "name": "taxesAmountCents", "description": null, @@ -22240,6 +22252,35 @@ "inputFields": null, "enumValues": null }, + { + "kind": "ENUM", + "name": "InvoiceTaxStatusTypeEnum", + "description": null, + "interfaces": null, + "possibleTypes": null, + "fields": null, + "inputFields": null, + "enumValues": [ + { + "name": "pending", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "succeeded", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "failed", + "description": null, + "isDeprecated": false, + "deprecationReason": null + } + ] + }, { "kind": "ENUM", "name": "InvoiceTypeEnum", diff --git a/spec/graphql/mutations/invoices/finalize_spec.rb b/spec/graphql/mutations/invoices/finalize_spec.rb index 97884e915528..1b14373f7cf9 100644 --- a/spec/graphql/mutations/invoices/finalize_spec.rb +++ b/spec/graphql/mutations/invoices/finalize_spec.rb @@ -15,6 +15,7 @@ finalizeInvoice(input: $input) { id status + taxStatus } } GQL @@ -44,4 +45,35 @@ end end end + + context 'with tax provider' do + let(:integration) { create(:anrok_integration, organization:) } + let(:integration_customer) { create(:anrok_customer, integration:, customer:) } + + before do + integration_customer + end + + it 'returns pending invoice' do + freeze_time do + result = execute_graphql( + current_user: membership.user, + current_organization: organization, + permissions: required_permission, + query: mutation, + variables: { + input: {id: invoice.id} + } + ) + + result_data = result['data']['finalizeInvoice'] + + aggregate_failures do + expect(result_data['id']).to be_present + expect(result_data['status']).to eq('pending') + expect(result_data['taxStatus']).to eq('pending') + end + end + end + end end