super_good-solidus_taxjar 0.18.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +48 -6
  3. data/CHANGELOG.md +103 -1
  4. data/Gemfile +26 -10
  5. data/PULL_REQUEST_TEMPLATE.md +0 -1
  6. data/README.md +299 -39
  7. data/Rakefile +3 -0
  8. data/app/controllers/spree/admin/taxjar_settings_controller.rb +86 -1
  9. data/app/controllers/spree/admin/taxjar_transactions_controller.rb +37 -0
  10. data/app/controllers/spree/admin/transaction_sync_batches_controller.rb +18 -0
  11. data/app/jobs/super_good/solidus_taxjar/backfill_transaction_sync_batch_job.rb +23 -0
  12. data/app/jobs/super_good/solidus_taxjar/replace_transaction_job.rb +26 -0
  13. data/app/jobs/super_good/solidus_taxjar/report_transaction_job.rb +22 -0
  14. data/app/models/super_good/solidus_taxjar/configuration.rb +27 -0
  15. data/app/models/super_good/solidus_taxjar/order_transaction.rb +16 -0
  16. data/app/models/super_good/solidus_taxjar/refund_transaction.rb +13 -0
  17. data/app/models/super_good/solidus_taxjar/transaction_sync_batch.rb +11 -0
  18. data/app/models/super_good/solidus_taxjar/transaction_sync_log.rb +8 -0
  19. data/app/overrides/spree/admin/orders_controller_override.rb +12 -0
  20. data/app/overrides/spree/admin/shared/_order_submenu/add_taxjar_sync_history_tab.html.erb.deface +6 -0
  21. data/app/overrides/spree/admin/shared/_order_summary/add_taxjar_reported_at.html.erb.deface +30 -0
  22. data/app/overrides/spree/admin/shared/_taxes_tabs/add_configuration_menu_items.html.erb.deface +5 -0
  23. data/app/overrides/super_good/solidus_taxjar/spree/order_override.rb +21 -0
  24. data/app/views/spree/admin/orders/taxjar_transactions.html.erb +4 -0
  25. data/app/views/spree/admin/shared/_transaction_sync_log_table.html.erb +35 -0
  26. data/app/views/spree/admin/taxjar_settings/_nexus_regions.html.erb +23 -0
  27. data/app/views/spree/admin/taxjar_settings/_tax_categories.html.erb +41 -0
  28. data/app/views/spree/admin/taxjar_settings/edit.html.erb +17 -0
  29. data/app/views/spree/admin/taxjar_settings/edit_no_api_key.html.erb +21 -0
  30. data/app/views/spree/admin/transaction_sync_batches/index.html.erb +50 -0
  31. data/app/views/spree/admin/transaction_sync_batches/show.html.erb +7 -0
  32. data/bin/console +2 -0
  33. data/bin/rails-engine +1 -1
  34. data/bin/sandbox +43 -36
  35. data/bin/setup +3 -3
  36. data/config/routes.rb +13 -1
  37. data/db/migrate/20210908205201_create_taxjar_order_transactions.rb +16 -0
  38. data/db/migrate/20211008175113_create_taxjar_refund_transaction.rb +15 -0
  39. data/db/migrate/20211008183858_add_transaction_date_to_order_transaction.rb +5 -0
  40. data/db/migrate/20211119143354_create_configuration.rb +8 -0
  41. data/db/migrate/20220405213958_create_transaction_sync_batches.rb +7 -0
  42. data/db/migrate/20220405215225_create_transaction_sync_logs.rb +14 -0
  43. data/db/migrate/20220908181655_add_dates_to_transaction_sync_batch.rb +6 -0
  44. data/db/migrate/20220912182210_allow_null_transaction_sync_batches_on_logs.rb +5 -0
  45. data/db/migrate/20230320211309_add_refund_transaction_to_sync_logs.rb +5 -0
  46. data/lib/generators/super_good/solidus_taxjar/install/install_generator.rb +68 -0
  47. data/lib/super_good/solidus_taxjar/api.rb +41 -9
  48. data/lib/super_good/solidus_taxjar/api_params.rb +92 -25
  49. data/lib/super_good/solidus_taxjar/backfill_transactions.rb +11 -0
  50. data/lib/super_good/solidus_taxjar/cached_api.rb +23 -0
  51. data/lib/super_good/solidus_taxjar/calculator_helper.rb +33 -4
  52. data/lib/super_good/solidus_taxjar/discount_calculator.rb +1 -1
  53. data/lib/super_good/solidus_taxjar/overrides/request_override.rb +15 -0
  54. data/lib/super_good/solidus_taxjar/reportable.rb +91 -0
  55. data/lib/super_good/solidus_taxjar/reporting.rb +44 -0
  56. data/lib/super_good/solidus_taxjar/spree/legacy_reporting_subscriber.rb +41 -0
  57. data/lib/super_good/solidus_taxjar/spree/reporting_subscriber.rb +40 -0
  58. data/lib/super_good/solidus_taxjar/tax_calculator.rb +7 -1
  59. data/lib/super_good/solidus_taxjar/testing_support/factories/address_factory.rb +11 -0
  60. data/lib/super_good/solidus_taxjar/testing_support/factories/configuration_factory.rb +11 -0
  61. data/lib/super_good/solidus_taxjar/testing_support/factories/order_transaction_factory.rb +22 -0
  62. data/lib/super_good/solidus_taxjar/testing_support/factories/refund_transaction_factory.rb +7 -0
  63. data/lib/super_good/solidus_taxjar/testing_support/factories/transaction_sync_batch_factory.rb +9 -0
  64. data/lib/super_good/solidus_taxjar/testing_support/factories/transaction_sync_log_factory.rb +18 -0
  65. data/lib/super_good/solidus_taxjar/transaction_id_generator.rb +45 -0
  66. data/lib/super_good/solidus_taxjar/version.rb +1 -1
  67. data/lib/super_good/solidus_taxjar.rb +29 -2
  68. data/spec/features/spree/admin/backfill_transactions_spec.rb +138 -0
  69. data/spec/features/spree/admin/refund_spec.rb +167 -0
  70. data/spec/features/spree/admin/reporting_to_taxjar_spec.rb +156 -0
  71. data/spec/features/spree/admin/taxjar_settings_spec.rb +58 -16
  72. data/spec/features/spree/checkout_spec.rb +58 -0
  73. data/spec/fixtures/cassettes/Admin_TaxJar_Settings/GET_sync_nexus_regions/Taxjar_API_token_is_not_set/doesn_t_make_a_request_for_the_nexus_regions.yml +57 -0
  74. data/spec/fixtures/cassettes/Admin_TaxJar_Settings/GET_sync_tax_categories/Taxjar_API_token_is_not_set/doesn_t_make_a_request_for_the_tax_categories.yml +57 -0
  75. data/spec/fixtures/cassettes/Admin_TaxJar_Settings/Taxjar_settings_tab/Taxjar_API_token_is_set/shows_the_settings_page.yml +2437 -0
  76. data/spec/fixtures/cassettes/Admin_TaxJar_Settings/Taxjar_settings_tab/Taxjar_API_token_isn_t_set/doesn_t_show_any_other_TaxJar_features.yml +57 -0
  77. data/spec/fixtures/cassettes/Admin_TaxJar_Settings/Taxjar_settings_tab/Taxjar_API_token_isn_t_set/shows_a_descriptive_error_message.yml +57 -0
  78. data/spec/fixtures/cassettes/Admin_TaxJar_Settings/Taxjar_settings_tab/Taxjar_reporting_is_enabled/shows_that_reporting_is_enabled.yml +2382 -0
  79. data/spec/fixtures/cassettes/Admin_TaxJar_Settings/Taxjar_settings_tab/order_is_shipped/the_user_backfills_their_transactions.yml +2511 -0
  80. data/spec/fixtures/cassettes/Admin_TaxJar_Settings/Taxjar_settings_tab/the_user_navigates_to_the_TaxJar_Settings.yml +2382 -0
  81. data/spec/fixtures/cassettes/Admin_Transaction_Sync_Batches/user_has_a_shipped_order/starts_a_transaction_backfill.yml +370 -0
  82. data/spec/fixtures/cassettes/Reporting_orders_to_TaxJar/shipping_a_complete_and_paid_order.yml +310 -0
  83. data/spec/fixtures/cassettes/Reporting_orders_to_TaxJar/updating_an_order_which_was_not_reported_due_to_failure/it_reports_the_order_instead_of_trying_to_replace_it.yml +794 -0
  84. data/spec/fixtures/cassettes/Reporting_orders_to_TaxJar/with_an_order_with_invalid_zipcode/retry_of_a_previously_failed_transaction_sync.yml +418 -0
  85. data/spec/fixtures/cassettes/Spree_Admin_TransactionSyncBatchesController/_create/creates_a_batch.yml +250 -0
  86. data/spec/fixtures/cassettes/Spree_Admin_TransactionSyncBatchesController/_create/creates_a_log_in_the_batch_with_an_order.yml +250 -0
  87. data/spec/fixtures/cassettes/Spree_Admin_TransactionSyncBatchesController/_create/user_supplies_a_start_date/creates_a_batch.yml +250 -0
  88. data/spec/fixtures/cassettes/Spree_Admin_TransactionSyncBatchesController/_create/user_supplies_a_start_date/user_supplies_start_and_end_date/creates_a_batch.yml +250 -0
  89. data/spec/fixtures/cassettes/SuperGood_SolidusTaxjar_CalculatorHelper/_taxable_address_/when_taxable_address_check_returns_true/with_US_address/when_the_address_is_not_within_a_nexus_region/1_3_2_2_2_1.yml +58 -0
  90. data/spec/fixtures/cassettes/SuperGood_SolidusTaxjar_CalculatorHelper/_taxable_address_/when_taxable_address_check_returns_true/with_US_address/when_the_address_is_within_a_nexus_region/1_3_2_2_1_1.yml +58 -0
  91. data/spec/fixtures/cassettes/SuperGood_SolidusTaxjar_Reporting/_refund_and_create_transaction/when_Taxjar_cannot_create_a_refund_transaction/doesn_t_create_a_new_transaction.yml +393 -0
  92. data/spec/fixtures/cassettes/SuperGood_SolidusTaxjar_Reporting/_refund_and_create_transaction/when_Taxjar_cannot_create_a_refund_transaction/raises_an_error.yml +393 -0
  93. data/spec/fixtures/cassettes/Taxjar_API_Request/logging_is_disabled/doesn_t_call_the_logger.yml +158 -0
  94. data/spec/fixtures/cassettes/Taxjar_API_Request/logging_is_enabled/calls_the_logger.yml +158 -0
  95. data/spec/fixtures/cassettes/features/spree/admin/checkout.yml +238 -0
  96. data/spec/fixtures/cassettes/features/spree/admin/refund.yml +1162 -0
  97. data/spec/jobs/super_good/solidus_taxjar/backfill_transaction_sync_batch_job_spec.rb +117 -0
  98. data/spec/jobs/super_good/solidus_taxjar/replace_transaction_job_spec.rb +95 -0
  99. data/spec/jobs/super_good/solidus_taxjar/report_transaction_job_spec.rb +76 -0
  100. data/spec/models/super_good/solidus_taxjar/configuration_spec.rb +79 -0
  101. data/spec/models/super_good/solidus_taxjar/order_transaction_spec.rb +36 -0
  102. data/spec/models/super_good/solidus_taxjar/transaction_sync_batch_spec.rb +48 -0
  103. data/spec/requests/spree/admin/order_request_spec.rb +121 -0
  104. data/spec/requests/spree/admin/taxjar_settings_request_spec.rb +198 -0
  105. data/spec/requests/spree/admin/taxjar_transactions_request_spec.rb +62 -0
  106. data/spec/requests/spree/admin/transaction_sync_batches_request_spec.rb +82 -0
  107. data/spec/spec_helper.rb +46 -3
  108. data/spec/subscribers/super_good/solidus_taxjar/spree/reporting_subscriber_spec.rb +278 -0
  109. data/spec/super_good/solidus_taxjar/addresses_spec.rb +0 -14
  110. data/spec/super_good/solidus_taxjar/api_params_spec.rb +261 -89
  111. data/spec/super_good/solidus_taxjar/api_spec.rb +152 -29
  112. data/spec/super_good/solidus_taxjar/backfill_transactions_spec.rb +24 -0
  113. data/spec/super_good/solidus_taxjar/cached_api_spec.rb +58 -0
  114. data/spec/super_good/solidus_taxjar/calculator_helper_spec.rb +131 -0
  115. data/spec/super_good/solidus_taxjar/discount_calculator_spec.rb +19 -2
  116. data/spec/super_good/solidus_taxjar/reportable_spec.rb +194 -0
  117. data/spec/super_good/solidus_taxjar/reporting_spec.rb +243 -0
  118. data/spec/super_good/solidus_taxjar/tax_calculator_spec.rb +19 -19
  119. data/spec/super_good/solidus_taxjar/tax_rate_calculator_spec.rb +8 -3
  120. data/spec/super_good/solidus_taxjar/transaction_id_generator_spec.rb +77 -0
  121. data/spec/super_good/solidus_taxjar_spec.rb +84 -0
  122. data/spec/support/checkoutable_store_shared_context.rb +19 -0
  123. data/spec/support/solidus_events_helper.rb +26 -0
  124. data/spec/taxjar/api/request_spec.rb +52 -0
  125. data/super_good-solidus_taxjar.gemspec +3 -2
  126. metadata +169 -17
  127. data/app/decorators/super_good/solidus_taxjar/spree/order_updater/fire_recalculated_event.rb +0 -18
  128. data/app/overrides/spree/admin/shared/_configuration_menu.rb +0 -11
  129. data/app/views/spree/admin/taxjar_settings/show.html.erb +0 -13
  130. data/spec/models/spree/order_updater_spec.rb +0 -12
@@ -1,7 +1,92 @@
1
1
  module Spree
2
2
  module Admin
3
3
  class TaxjarSettingsController < Spree::Admin::BaseController
4
- def show
4
+ helper_method :taxjar_tax_category_option
5
+
6
+ def edit
7
+ if ENV["TAXJAR_API_KEY"].blank?
8
+ flash[:error] = "You must provide a TaxJar API token to use this extension."
9
+ render "edit_no_api_key"
10
+ else
11
+ @configuration = SuperGood::SolidusTaxjar.configuration
12
+ @nexus_regions = cached_api.nexus_regions || []
13
+ @tax_categories = cached_tax_categories
14
+ end
15
+ end
16
+
17
+ def update
18
+ configuration_update if params[:super_good_solidus_taxjar_configuration]
19
+ tax_category_update if params[:tax_category]
20
+ redirect_back(fallback_location: spree.admin_taxjar_settings_path)
21
+ end
22
+
23
+ def sync_nexus_regions
24
+ api_sync do
25
+ cached_api.nexus_regions(refresh: true)
26
+ flash[:success] = "Updated with new Nexus Regions"
27
+ end
28
+ end
29
+
30
+ def sync_tax_categories
31
+ api_sync do
32
+ cached_tax_categories
33
+ flash[:success] = "Updated with new tax categories"
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def cached_api
40
+ SuperGood::SolidusTaxjar::CachedApi.new
41
+ end
42
+
43
+ def configuration_params
44
+ params_hash = params.require(:super_good_solidus_taxjar_configuration).permit(:preferred_reporting_enabled, :preferred_reporting_enabled_at_integer)
45
+ {
46
+ preferred_reporting_enabled_at_integer: params_hash[:preferred_reporting_enabled] == "1" ? DateTime.now.to_i : nil
47
+ }
48
+ end
49
+
50
+ def tax_category_params
51
+ params.require(:tax_category)
52
+ end
53
+
54
+ def api_sync
55
+ begin
56
+ yield
57
+ rescue Taxjar::Error => exception
58
+ flash[:error] = "Failed to complete request to TaxJar: #{exception.message}"
59
+ end
60
+ redirect_back(fallback_location: spree.admin_taxjar_settings_path)
61
+ end
62
+
63
+ def cached_tax_categories
64
+ Rails.cache.fetch(
65
+ :tax_categories,
66
+ expires_in: 30.days
67
+ ) { SuperGood::SolidusTaxjar.api.tax_categories }
68
+ end
69
+
70
+ def configuration_update
71
+ if SuperGood::SolidusTaxjar.configuration.update(configuration_params)
72
+ flash[:success] = "TaxJar settings updated!"
73
+ else
74
+ flash[:alert] = "Failed to update settings!"
75
+ end
76
+ end
77
+
78
+ def tax_category_update
79
+ if Spree::TaxCategory.find(tax_category_params[:id]).update(tax_code: params[:tax_code_id])
80
+ flash[:success] = "Tax category #{tax_category_params[:name]} tax code updated with #{params[:tax_code_id]}!"
81
+ else
82
+ flash[:alert] = "Failed to update tax category #{tax_category_params[:name]}!"
83
+ end
84
+ end
85
+
86
+ def taxjar_tax_category_option(tax_code)
87
+ selected_tax_category = @tax_categories.detect{|taxjar_tax_category| taxjar_tax_category.product_tax_code == tax_code}
88
+ return unless selected_tax_category
89
+ ["#{selected_tax_category.name} (#{selected_tax_category.product_tax_code})", selected_tax_category.product_tax_code]
5
90
  end
6
91
  end
7
92
  end
@@ -0,0 +1,37 @@
1
+ module Spree
2
+ module Admin
3
+ class TaxjarTransactionsController < Spree::Admin::BaseController
4
+ include SuperGood::SolidusTaxjar::Reportable
5
+
6
+ def retry
7
+ order = Spree::Order.find_by number: params[:order_id]
8
+
9
+ if transaction_replaceable? order
10
+ replace_transaction order
11
+ flash[:notice] = "Queued transaction sync job"
12
+ elsif order_reportable? order
13
+ report_transaction order
14
+ flash[:notice] = "Queued transaction sync job"
15
+ else
16
+ flash[:error] = "Could not retry sync successfully"
17
+ end
18
+
19
+ redirect_to taxjar_transactions_admin_order_path(params[:order_id])
20
+ end
21
+
22
+ private
23
+
24
+ def report_transaction(order)
25
+ with_reportable(order) do
26
+ SuperGood::SolidusTaxjar::ReportTransactionJob.perform_later(order)
27
+ end
28
+ end
29
+
30
+ def replace_transaction(order)
31
+ with_replaceable(order) do
32
+ SuperGood::SolidusTaxjar::ReplaceTransactionJob.perform_later(order)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,18 @@
1
+ module Spree
2
+ module Admin
3
+ class TransactionSyncBatchesController < Spree::Admin::BaseController
4
+ def index
5
+ @batches = SuperGood::SolidusTaxjar::TransactionSyncBatch.all.page(params[:page]).per(params[:per_page])
6
+ end
7
+
8
+ def show
9
+ @batch = SuperGood::SolidusTaxjar::TransactionSyncBatch.find(params[:id])
10
+ end
11
+
12
+ def create
13
+ batch = ::SuperGood::SolidusTaxjar::BackfillTransactions.new.call(start_date: params[:start_date], end_date: params[:end_date])
14
+ redirect_to spree.admin_transaction_sync_batch_path(batch)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SuperGood
4
+ module SolidusTaxjar
5
+ class BackfillTransactionSyncBatchJob < ApplicationJob
6
+ queue_as { SuperGood::SolidusTaxjar.job_queue }
7
+
8
+ def perform(transaction_sync_batch)
9
+ complete_orders = ::Spree::Order.complete.where(shipment_state: 'shipped')
10
+ if transaction_sync_batch.start_date
11
+ complete_orders = complete_orders.where("completed_at >= ?", transaction_sync_batch.start_date.beginning_of_day)
12
+ end
13
+ if transaction_sync_batch.end_date
14
+ complete_orders = complete_orders.where("completed_at <= ?", transaction_sync_batch.end_date.end_of_day)
15
+ end
16
+ complete_orders.find_each do |order|
17
+ next if order.taxjar_order_transactions.any?
18
+ SuperGood::SolidusTaxjar::ReportTransactionJob.perform_later(order, transaction_sync_batch)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SuperGood
4
+ module SolidusTaxjar
5
+ class ReplaceTransactionJob < ApplicationJob
6
+ queue_as { SuperGood::SolidusTaxjar.job_queue }
7
+
8
+ def perform(order)
9
+ order_transaction = SuperGood::SolidusTaxjar.reporting.refund_and_create_new_transaction(order)
10
+
11
+ SuperGood::SolidusTaxjar::TransactionSyncLog.create!(
12
+ order: order,
13
+ order_transaction: order_transaction,
14
+ status: :success
15
+ )
16
+
17
+ rescue Taxjar::Error => exception
18
+ SuperGood::SolidusTaxjar::TransactionSyncLog.create!(
19
+ order: order,
20
+ status: :error,
21
+ error_message: exception.message
22
+ )
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SuperGood
4
+ module SolidusTaxjar
5
+ class ReportTransactionJob < ApplicationJob
6
+ queue_as { SuperGood::SolidusTaxjar.job_queue }
7
+
8
+ def perform(order, transaction_sync_batch = nil)
9
+ transaction_sync_log = SuperGood::SolidusTaxjar::TransactionSyncLog.create!(
10
+ transaction_sync_batch: transaction_sync_batch,
11
+ order: order
12
+ )
13
+ begin
14
+ order_transaction = SuperGood::SolidusTaxjar.reporting.show_or_create_transaction(order)
15
+ transaction_sync_log.update!(order_transaction: order_transaction, status: :success)
16
+ rescue StandardError => exception
17
+ transaction_sync_log.update!(status: :error, error_message: exception.message)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,27 @@
1
+ require 'spree/preferences/persistable'
2
+
3
+ module SuperGood
4
+ module SolidusTaxjar
5
+ class Configuration < ::Spree::Base
6
+ include ::Spree::Preferences::Persistable
7
+
8
+ self.table_name = 'solidus_taxjar_configuration'
9
+ preference :reporting_enabled_at_integer, :integer, default: nil
10
+
11
+ def preferred_reporting_enabled
12
+ preferred_reporting_enabled_at_integer.present? &&
13
+ DateTime.current.after?(preferred_reporting_enabled_at)
14
+ end
15
+
16
+ def preferred_reporting_enabled_at
17
+ Time.at(SuperGood::SolidusTaxjar.configuration.preferred_reporting_enabled_at_integer).to_datetime
18
+ end
19
+
20
+ class << self
21
+ def default
22
+ first || create
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,16 @@
1
+ module SuperGood
2
+ module SolidusTaxjar
3
+ class OrderTransaction < ActiveRecord::Base
4
+ belongs_to :order, class_name: "Spree::Order"
5
+
6
+ has_one :refund_transaction
7
+
8
+ validates_presence_of :transaction_id
9
+ validates_presence_of :transaction_date
10
+
11
+ def self.latest_for(order)
12
+ where(order: order).order(transaction_date: :desc, created_at: :desc).limit(1).first
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,13 @@
1
+ module SuperGood
2
+ module SolidusTaxjar
3
+ class RefundTransaction < ActiveRecord::Base
4
+ belongs_to :order_transaction
5
+
6
+ delegate :order, to: :order_transaction
7
+
8
+ validates_presence_of :order_transaction
9
+ validates_presence_of :transaction_id
10
+ validates_presence_of :transaction_date
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ class SuperGood::SolidusTaxjar::TransactionSyncBatch < ApplicationRecord
2
+ has_many :transaction_sync_logs
3
+ has_many :orders, through: :transaction_sync_logs
4
+
5
+ def status
6
+ return 'processing' if transaction_sync_logs.processing.any?
7
+ return 'error' if transaction_sync_logs.error.any?
8
+
9
+ 'success'
10
+ end
11
+ end
@@ -0,0 +1,8 @@
1
+ class SuperGood::SolidusTaxjar::TransactionSyncLog < ApplicationRecord
2
+ belongs_to :transaction_sync_batch, optional: true
3
+ belongs_to :order, class_name: "Spree::Order"
4
+ belongs_to :order_transaction, optional: true
5
+ delegate :refund_transaction, to: :order_transaction, :allow_nil => true
6
+
7
+ enum status: [:processing, :success, :error]
8
+ end
@@ -0,0 +1,12 @@
1
+ module Spree
2
+ module Admin
3
+ module OrdersControllerOverride
4
+ # FIXME: Move this to TaxJar transactions controller.
5
+ def taxjar_transactions
6
+ load_order
7
+ end
8
+
9
+ Spree::Admin::OrdersController.prepend self
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,6 @@
1
+
2
+ <!-- insert_bottom "[data-hook='admin_order_tabs']" -->
3
+
4
+ <li class="<%= "active" if current == "TaxJar Sync History" %>" data-hook='admin_order_tabs_order_details'>
5
+ <%= link_to "TaxJar Sync History", spree.taxjar_transactions_admin_order_path(@order) %>
6
+ </li>
@@ -0,0 +1,30 @@
1
+
2
+ <!-- insert_bottom "[id='order_tab_summary'] > .additional-info" -->
3
+
4
+ <% content_for :head do %>
5
+ <style>
6
+ .pill-success {
7
+ background: #c8d8e8;
8
+ }
9
+ </style>
10
+ <% end %>
11
+
12
+ <% last_success_sync_log = @order.taxjar_transaction_sync_logs.success.order(:created_at).last %>
13
+ <% last_sync_log = @order.taxjar_transaction_sync_logs.order(:created_at).last %>
14
+ <dt>Reported to TaxJar at:</dt>
15
+ <dd> <%= last_success_sync_log ? pretty_time(last_success_sync_log.created_at) : "-" %></dd>
16
+ <dt>TaxJar Sync: </dt>
17
+ <dd>
18
+ <% last_sync_log_status = if last_sync_log
19
+ last_sync_log.status
20
+ else
21
+ SuperGood::SolidusTaxjar.configuration.preferred_reporting_enabled ?
22
+ "pending" :
23
+ "disabled"
24
+ end
25
+ %>
26
+ <span class="pill pill-<%= last_sync_log_status %>">
27
+ <%= last_sync_log_status.capitalize %>
28
+ </span>
29
+ </dd>
30
+ <dt><%= link_to("TaxJar Sync History", spree.taxjar_transactions_admin_order_path(@order)) %></dt>
@@ -0,0 +1,5 @@
1
+ <!-- insert_bottom "[data-hook='admin_settings_taxes_tabs']" -->
2
+
3
+ <%= configurations_sidebar_menu_item "TaxJar Settings", edit_admin_taxjar_settings_path %>
4
+
5
+ <%= configurations_sidebar_menu_item "TaxJar Backfill", admin_transaction_sync_batches_path %>
@@ -0,0 +1,21 @@
1
+ module SuperGood
2
+ module SolidusTaxjar
3
+ module Spree
4
+ module OrderOverride
5
+ def self.prepended(base)
6
+ base.has_many :taxjar_order_transactions,
7
+ class_name: "SuperGood::SolidusTaxjar::OrderTransaction",
8
+ dependent: :destroy,
9
+ inverse_of: :order
10
+
11
+ base.has_many :taxjar_transaction_sync_logs,
12
+ -> { order(:created_at) },
13
+ class_name: "SuperGood::SolidusTaxjar::TransactionSyncLog",
14
+ inverse_of: :order
15
+ end
16
+
17
+ ::Spree::Order.prepend self
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,4 @@
1
+ <%= render partial: 'spree/admin/shared/order_tabs', locals: { current: 'TaxJar Sync History' } %>
2
+ <% admin_breadcrumb("TaxJar Sync History") %>
3
+
4
+ <%= render 'spree/admin/shared/transaction_sync_log_table', transaction_sync_logs: @order.taxjar_transaction_sync_logs %>
@@ -0,0 +1,35 @@
1
+ <table id="transaction_sync_logs" class="index">
2
+ <thead>
3
+ <tr>
4
+ <th>Log ID</th>
5
+ <th class="wrap-text">Order</th>
6
+ <th class="wrap-text">Txn ID</th>
7
+ <th class="wrap-text">Refund Txn ID</th>
8
+ <th class="wrap-text">Status</th>
9
+ <th class="wrap-text">Error</th>
10
+ <th class="wrap-text">Created at</th>
11
+ <th class="wrap-text">Updated at</th>
12
+ <th class="wrap-text"></th>
13
+ </tr>
14
+ </thead>
15
+ <tbody>
16
+ <% transaction_sync_logs.each.with_index(1) do |log, index| %>
17
+ <tr>
18
+ <td><%= log.id %></td>
19
+ <td><%= link_to log.order.number, spree.edit_admin_order_path(log.order) %></td>
20
+ <td><%= log.order_transaction&.transaction_id || "-" %></td>
21
+ <td><%= log.refund_transaction&.transaction_id || "-" %></td>
22
+ <td><%= log.status.capitalize %></td>
23
+ <td style="white-space: pre-wrap; width: 150px; overflow-wrap: anywhere;"><%= log.error_message %></td>
24
+ <td><%= log.created_at %></td>
25
+ <td><%= log.updated_at %></td>
26
+ <td class="actions">
27
+ <% # If the latest log is an error show a retry. %>
28
+ <% if log.error? && transaction_sync_logs.count == index %>
29
+ <%= link_to_with_icon('repeat', "Retry", admin_order_taxjar_transaction_retry_path(log.order), {method: :post}) %>
30
+ <% end %>
31
+ </td>
32
+ </tr>
33
+ <% end %>
34
+ </tbody>
35
+ </table>
@@ -0,0 +1,23 @@
1
+ <fieldset>
2
+ <legend>Nexus Regions</legend>
3
+ <table>
4
+ <thead>
5
+ <tr>
6
+ <th>Country Code</th>
7
+ <th>Country</th>
8
+ <th>Region Code</th>
9
+ <th>Region</th>
10
+ </tr>
11
+ </thead>
12
+ <% @nexus_regions.each do |region| %>
13
+ <tr>
14
+ <td><%= region.country_code %></td>
15
+ <td><%= region.country %></td>
16
+ <td><%= region.region_code %></td>
17
+ <td><%= region.region %></td>
18
+ </tr>
19
+ <% end %>
20
+ </table>
21
+ <a class="btn btn-primary" href="<%= spree.admin_taxjar_settings_sync_nexus_regions_path %>">Sync Nexus Regions</a>
22
+ <a class="btn btn-outline-primary" href="https://app.taxjar.com/account#states">Go to TaxJar to configure states</a>
23
+ </fieldset>
@@ -0,0 +1,41 @@
1
+ <fieldset>
2
+ <legend>Tax Categories</legend>
3
+ <p>Select TaxJar tax codes and apply them to your Solidus tax categories.</p>
4
+ <table data-hook="admin_taxjar_tax_categories_sync">
5
+ <thead>
6
+ <tr>
7
+ <th>Name</th>
8
+ <th>Tax Code</th>
9
+ <th class="align-right">TaxJar Tax Code</th>
10
+ <th></th>
11
+ </tr>
12
+ </thead>
13
+ <% Spree::TaxCategory.all.each do |category| %>
14
+ <%= form_for category, url: admin_taxjar_settings_path, method: :put, local: true do |form| %>
15
+ <tr>
16
+ <td>
17
+ <%= category.name %>
18
+ <%= form.hidden_field(:name) %>
19
+ </td>
20
+ <td>
21
+ <%= category.tax_code %>
22
+ <%= form.hidden_field(:tax_code) %>
23
+ <%= form.hidden_field(:id) %>
24
+ </td>
25
+ <td class="align-right">
26
+ <%= select_tag "tax_code_id",
27
+ options_for_select(
28
+ @tax_categories.map{|taxjar_tax_category|
29
+ taxjar_tax_category_option(taxjar_tax_category.product_tax_code)
30
+ },
31
+ category.tax_code
32
+ ),
33
+ prompt: "Select New Tax Code",
34
+ class: "select2" %>
35
+ <%= form.submit %>
36
+ </td>
37
+ </tr>
38
+ <% end %>
39
+ <% end %>
40
+ </table>
41
+ </fieldset>
@@ -0,0 +1,17 @@
1
+ <%= render 'spree/admin/shared/taxes_tabs' %>
2
+
3
+ <% content_for :page_title do %>
4
+ <%= "Taxjar Settings" %>
5
+ <% end %>
6
+
7
+ <%= render 'nexus_regions' %>
8
+ <%= render 'tax_categories' %>
9
+ <%= form_with model: @configuration, url: admin_taxjar_settings_path, method: :put, local: true do |form| %>
10
+ <%= render "spree/admin/shared/preference_fields/boolean",
11
+ attribute: :preferred_reporting_enabled,
12
+ label: "Transaction Sync",
13
+ form: form
14
+ %>
15
+ <p>Sync orders and refund with TaxJar for automated sales tax reporting and filing. Complete and closed transactions sync automatically on update.</p>
16
+ <%= form.submit %>
17
+ <% end %>
@@ -0,0 +1,21 @@
1
+ <p>
2
+ You must provide a TaxJar API token to use this extension.
3
+
4
+ <%= link_to "Sign up for TaxJar",
5
+ "https://app.taxjar.com/api_sign_up",
6
+ rel: "noreferrer",
7
+ target: "_blank" %>
8
+
9
+ and provide your API key. See the extension documentation for details on
10
+ providing this token to the extension.
11
+ </p>
12
+ <p>
13
+ <emph>
14
+ For more help in aquiring a TaxJar API token, see
15
+
16
+ <%= link_to "How do I get a TaxJar sales tax API token?",
17
+ "https://support.taxjar.com/article/160-how-do-i-get-a-sales-tax-api-token",
18
+ target: "_blank",
19
+ rel: "noreferrer" %>
20
+ </emph>
21
+ </p>
@@ -0,0 +1,50 @@
1
+ <%= render 'spree/admin/shared/taxes_tabs' %>
2
+
3
+ <% content_for :page_title do %>
4
+ <%= "Transaction Sync Batches" %>
5
+ <% end %>
6
+
7
+ <%= form_with url: admin_transaction_sync_batches_path, method: :post, local: true do |f| %>
8
+ <div class="row" style="margin-bottom: 20px;">
9
+ <div class="col-3">
10
+ <%= f.label :start_date %>
11
+ <%= f.date_field :start_date %>
12
+ </div>
13
+ <div class="col-3">
14
+ <%= f.label :end_date %>
15
+ <%= f.date_field :end_date %>
16
+ </div>
17
+ <div class="col-3" style="align-self: flex-end;">
18
+ <%= f.submit "Backfill Transactions", class: "btn btn-primary" %>
19
+ </div>
20
+ </div>
21
+ <% end %>
22
+
23
+ <table id="transaction_sync_batches">
24
+ <thead>
25
+ <tr>
26
+ <th>Batch ID</th>
27
+ <th>Created at</th>
28
+ <th>Updated at</th>
29
+ <th>Processed Orders</th>
30
+ <th>Status</th>
31
+ <th></th>
32
+ </tr>
33
+ </thead>
34
+ <tbody>
35
+ <% @batches.each do |batch| %>
36
+ <tr>
37
+ <td><%= batch.id %></td>
38
+ <td><%= batch.created_at %></td>
39
+ <td><%= batch.updated_at %></td>
40
+ <td><%= batch.transaction_sync_logs.not_processing.count %>/<%= batch.transaction_sync_logs.count %></td>
41
+ <td><%= batch.status.capitalize %></td>
42
+ <td class='actions align-center'>
43
+ <%= link_to_edit_url admin_transaction_sync_batch_path(batch), title: "admin_transaction_sync_batch_show_#{dom_id(batch)}", no_text: true %>
44
+ </td>
45
+ </tr>
46
+ <% end %>
47
+ </tbody>
48
+ </table>
49
+
50
+ <%= paginate @batches, theme: "solidus_admin" %>
@@ -0,0 +1,7 @@
1
+ <%= render 'spree/admin/shared/taxes_tabs' %>
2
+
3
+ <% content_for :page_title do %>
4
+ <%= "Transaction Sync Batch #{@batch.id}" %>
5
+ <% end %>
6
+
7
+ <%= render 'spree/admin/shared/transaction_sync_log_table', transaction_sync_logs: @batch.transaction_sync_logs %>
data/bin/console CHANGED
@@ -1,5 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ # frozen_string_literal: true
4
+
3
5
  require "bundler/setup"
4
6
  require "super_good/solidus_taxjar"
5
7
  require "pry"
data/bin/rails-engine CHANGED
@@ -3,7 +3,7 @@
3
3
  # installed from the root of your application.
4
4
 
5
5
  ENGINE_ROOT = File.expand_path("..", __dir__)
6
- ENGINE_PATH = File.expand_path("../lib/solidus_taxjar/engine", __dir__)
6
+ ENGINE_PATH = File.expand_path("../lib/super_good-solidus_taxjar", __dir__)
7
7
 
8
8
  # Set up gems listed in the Gemfile.
9
9
  ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)