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,6 +1,9 @@
1
1
  require "spec_helper"
2
2
 
3
3
  RSpec.describe SuperGood::SolidusTaxjar::Api do
4
+ let(:api) { described_class.new(taxjar_client: dummy_client) }
5
+ let(:dummy_client) { instance_double ::Taxjar::Client }
6
+
4
7
  describe ".new" do
5
8
  subject { described_class.new }
6
9
 
@@ -31,12 +34,26 @@ RSpec.describe SuperGood::SolidusTaxjar::Api do
31
34
  end
32
35
  end
33
36
 
37
+ describe "#tax_categories" do
38
+ subject { api.tax_categories }
39
+
40
+ let(:tax_categories) {
41
+ [
42
+ instance_double(Taxjar::Category, name: "Clothing"),
43
+ instance_double(Taxjar::Category, name: "Digital Goods")
44
+ ]
45
+ }
46
+
47
+ it "responds with a list of tax categories" do
48
+ allow(dummy_client).to receive(:categories).and_return(tax_categories)
49
+
50
+ expect(subject).to eq(tax_categories)
51
+ end
52
+ end
34
53
 
35
54
  describe "#tax_for" do
36
55
  subject { api.tax_for order }
37
56
 
38
- let(:api) { described_class.new(taxjar_client: dummy_client) }
39
- let(:dummy_client) { instance_double ::Taxjar::Client }
40
57
  let(:order) { Spree::Order.new }
41
58
 
42
59
  before do
@@ -57,8 +74,6 @@ RSpec.describe SuperGood::SolidusTaxjar::Api do
57
74
  describe "tax_rate_for" do
58
75
  subject { api.tax_rate_for address }
59
76
 
60
- let(:api) { described_class.new(taxjar_client: dummy_client) }
61
- let(:dummy_client) { instance_double ::Taxjar::Client }
62
77
  let(:address) { Spree::Address.new }
63
78
  let(:tax_rate) { 0.04 }
64
79
  let(:response) { double(rate: tax_rate) }
@@ -81,8 +96,6 @@ RSpec.describe SuperGood::SolidusTaxjar::Api do
81
96
  describe "#tax_rates_for" do
82
97
  subject { api.tax_rates_for address }
83
98
 
84
- let(:api) { described_class.new(taxjar_client: dummy_client) }
85
- let(:dummy_client) { instance_double ::Taxjar::Client }
86
99
  let(:address) { Spree::Address.new }
87
100
 
88
101
  before do
@@ -105,28 +118,47 @@ RSpec.describe SuperGood::SolidusTaxjar::Api do
105
118
 
106
119
  let(:api) { described_class.new(taxjar_client: dummy_client) }
107
120
  let(:dummy_client) { instance_double ::Taxjar::Client }
108
- let(:order) { Spree::Order.new }
121
+ let(:order) { create(:order_ready_to_ship, number: "R123") }
122
+
123
+ let(:dummy_response) do
124
+ instance_double(
125
+ ::Taxjar::Order,
126
+ transaction_id: "R123",
127
+ transaction_date: "2015-05-15T00:00:00Z"
128
+ )
129
+ end
109
130
 
110
- before do
111
- allow(SuperGood::SolidusTaxjar::ApiParams)
112
- .to receive(:transaction_params)
113
- .with(order)
114
- .and_return({transaction: "params"})
131
+ context "when the latest transaction ID is nil" do
132
+ before do
133
+ allow(SuperGood::SolidusTaxjar::ApiParams)
134
+ .to receive(:transaction_params)
135
+ .with(order, "R123")
136
+ .and_return({transaction: "params"})
115
137
 
116
- allow(dummy_client)
117
- .to receive(:create_order)
118
- .with({transaction: "params"})
119
- .and_return({some_kind_of: "response"})
138
+ allow(dummy_client)
139
+ .to receive(:create_order)
140
+ .with({transaction: "params"})
141
+ .and_return(dummy_response)
142
+ end
143
+
144
+ it { is_expected.to eq(dummy_response) }
120
145
  end
121
146
 
122
- it { is_expected.to eq({some_kind_of: "response"}) }
147
+ context "when the API call to create the transaction fails" do
148
+ before do
149
+ allow(dummy_client).to receive(:create_order).and_raise(Taxjar::Error)
150
+ end
151
+
152
+ it "does not create an `OrderTransaction` for the order" do
153
+ expect { subject }.to raise_error(Taxjar::Error)
154
+ expect(order.taxjar_order_transactions.count).to be_zero
155
+ end
156
+ end
123
157
  end
124
158
 
125
159
  describe "#update_transaction_for" do
126
160
  subject { api.update_transaction_for order }
127
161
 
128
- let(:api) { described_class.new(taxjar_client: dummy_client) }
129
- let(:dummy_client) { instance_double ::Taxjar::Client }
130
162
  let(:order) { Spree::Order.new }
131
163
 
132
164
  before do
@@ -144,11 +176,9 @@ RSpec.describe SuperGood::SolidusTaxjar::Api do
144
176
  it { is_expected.to eq({some_kind_of: "response"}) }
145
177
  end
146
178
 
147
- describe "#update_transaction_for" do
179
+ describe "#delete_transaction_for" do
148
180
  subject { api.delete_transaction_for order }
149
181
 
150
- let(:api) { described_class.new(taxjar_client: dummy_client) }
151
- let(:dummy_client) { instance_double ::Taxjar::Client }
152
182
  let(:order) { Spree::Order.new(number: "R111222333") }
153
183
 
154
184
  before do
@@ -161,11 +191,49 @@ RSpec.describe SuperGood::SolidusTaxjar::Api do
161
191
  it { is_expected.to eq({some_kind_of: "response"}) }
162
192
  end
163
193
 
194
+ describe "#show_latest_transaction_for" do
195
+ subject { api.show_latest_transaction_for order }
196
+
197
+ let(:order) { Spree::Order.new(number: "R111222333") }
198
+
199
+ context "with a persisted order transaction" do
200
+ before do
201
+ create(
202
+ :taxjar_order_transaction,
203
+ order: order,
204
+ transaction_id: "R111222333-42"
205
+ )
206
+ end
207
+
208
+ let(:order) { create(:order, number: "R111222333") }
209
+
210
+ it "uses the persisted transaction_id to fetch the TaxJar transaction" do
211
+ expect(dummy_client)
212
+ .to receive(:show_order)
213
+ .with("R111222333-42")
214
+ .and_return({some_kind_of: "response"})
215
+ expect(subject).to eq({some_kind_of: "response"})
216
+ end
217
+
218
+ context "TaxJar does not have an order transaction persisted" do
219
+ before do
220
+ allow(dummy_client)
221
+ .to receive(:show_order)
222
+ .and_raise(Taxjar::Error::NotFound)
223
+ end
224
+
225
+ it { is_expected.to eq nil }
226
+ end
227
+ end
228
+
229
+ context "without a persisted order transaction" do
230
+ it { is_expected.to eq nil }
231
+ end
232
+ end
233
+
164
234
  describe "#create_refund_for" do
165
235
  subject { api.create_refund_for reimbursement }
166
236
 
167
- let(:api) { described_class.new(taxjar_client: dummy_client) }
168
- let(:dummy_client) { instance_double ::Taxjar::Client }
169
237
  let(:reimbursement) { Spree::Reimbursement.new }
170
238
 
171
239
  before do
@@ -183,11 +251,69 @@ RSpec.describe SuperGood::SolidusTaxjar::Api do
183
251
  it { is_expected.to eq({some_kind_of: "response"}) }
184
252
  end
185
253
 
254
+ describe "#create_refund_transaction_for" do
255
+ subject { api.create_refund_transaction_for order }
256
+
257
+ let(:order) { create(:order_ready_to_ship, number: "R111222333") }
258
+
259
+ let(:taxjar_order) {
260
+ Taxjar::Order.new(
261
+ amount: 20,
262
+ sales_tax: 2,
263
+ shipping: 5
264
+ )
265
+ }
266
+
267
+ before do
268
+ allow(dummy_client)
269
+ .to receive(:show_order)
270
+ .with("R111222333-10")
271
+ .and_return(taxjar_order)
272
+
273
+ allow(SuperGood::SolidusTaxjar::ApiParams)
274
+ .to receive(:refund_transaction_params)
275
+ .with(order, taxjar_order)
276
+ .and_return({refund_transaction: "params"})
277
+
278
+ allow(dummy_client)
279
+ .to receive(:create_refund)
280
+ .with({refund_transaction: "params"})
281
+ .and_return({some_kind_of: "response"})
282
+ end
283
+
284
+ context "when no order transaction has been persisted" do
285
+ it "raises an exception" do
286
+ expect { subject }.to raise_error(
287
+ NotImplementedError,
288
+ "No latest TaxJar order transaction for #{order.number}. " \
289
+ "Backfilling TaxJar transaction orders from Solidus is not yet " \
290
+ "implemented."
291
+ )
292
+ end
293
+ end
294
+
295
+ context "when an order transaction has been persisted" do
296
+ before do
297
+ create(
298
+ :taxjar_order_transaction,
299
+ order: order,
300
+ transaction_id: "R111222333-10"
301
+ )
302
+ end
303
+
304
+ it "requests the latest transaction from TaxJar" do
305
+ expect(dummy_client).to receive(:show_order).with("R111222333-10")
306
+
307
+ subject
308
+ end
309
+
310
+ it { is_expected.to eq({some_kind_of: "response"}) }
311
+ end
312
+ end
313
+
186
314
  describe "#validate_spree_address" do
187
315
  subject { api.validate_spree_address spree_address }
188
316
 
189
- let(:api) { described_class.new(taxjar_client: dummy_client) }
190
- let(:dummy_client) { instance_double ::Taxjar::Client }
191
317
  let(:spree_address) { build :address }
192
318
 
193
319
  before do
@@ -208,9 +334,6 @@ RSpec.describe SuperGood::SolidusTaxjar::Api do
208
334
  describe "#nexus_regions" do
209
335
  subject { api.nexus_regions }
210
336
 
211
- let(:api) { described_class.new(taxjar_client: dummy_client) }
212
- let(:dummy_client) { instance_double ::Taxjar::Client }
213
-
214
337
  before do
215
338
  allow(dummy_client)
216
339
  .to receive(:nexus_regions)
@@ -0,0 +1,24 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe SuperGood::SolidusTaxjar::BackfillTransactions do
4
+ describe "#call" do
5
+ subject { described_class.new.call(start_date: start_date.to_s, end_date: end_date.to_s) }
6
+
7
+ let(:start_date) { 1.day.ago.to_date }
8
+ let(:end_date) { Date.today }
9
+
10
+ it "returns a new transaction sync batch" do
11
+ expect(subject).to be_a(SuperGood::SolidusTaxjar::TransactionSyncBatch)
12
+ end
13
+
14
+ it "has the start and end date" do
15
+ expect(subject).to have_attributes({start_date: start_date, end_date: end_date})
16
+ end
17
+
18
+ it "queues a job to backfill the transactions in the batch" do
19
+ expect { subject }
20
+ .to have_enqueued_job(SuperGood::SolidusTaxjar::BackfillTransactionSyncBatchJob)
21
+ .with(kind_of(SuperGood::SolidusTaxjar::TransactionSyncBatch))
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,58 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe SuperGood::SolidusTaxjar::CachedApi do
4
+ describe ".nexus_regions" do
5
+ subject { instance.nexus_regions }
6
+
7
+ let(:instance) { described_class.new(api: dummy_api) }
8
+
9
+ let(:dummy_api) do
10
+ instance_double(SuperGood::SolidusTaxjar::Api)
11
+ end
12
+
13
+ let(:nexus_region) { ::Taxjar::NexusRegion.new(region: "California") }
14
+
15
+ before do
16
+ allow(dummy_api).to receive(:nexus_regions).and_return(
17
+ [nexus_region]
18
+ )
19
+ end
20
+
21
+ it "makes a request to the TaxJar API" do
22
+ subject
23
+ expect(dummy_api).to have_received(:nexus_regions)
24
+ end
25
+
26
+ it "returns a list of nexus regions" do
27
+ expect(subject).to contain_exactly(nexus_region)
28
+ end
29
+
30
+ context "when nexus regions cached" do
31
+ before do
32
+ Rails.cache.write(:nexus_regions, [nexus_region])
33
+ end
34
+
35
+ it "doesn't make a request to the TaxJar API" do
36
+ subject
37
+ expect(dummy_api).to_not have_received(:nexus_regions)
38
+ end
39
+
40
+ it "returns a list of nexus regions" do
41
+ expect(subject).to contain_exactly(nexus_region)
42
+ end
43
+
44
+ context "with refresh true" do
45
+ subject { instance.nexus_regions(refresh: true) }
46
+
47
+ it "makes a request to the TaxJar API" do
48
+ subject
49
+ expect(dummy_api).to have_received(:nexus_regions)
50
+ end
51
+
52
+ it "returns a list of nexus regions" do
53
+ expect(subject).to contain_exactly(nexus_region)
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,131 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe SuperGood::SolidusTaxjar::CalculatorHelper do
4
+ class TestProxy
5
+ extend SuperGood::SolidusTaxjar::CalculatorHelper
6
+ end
7
+
8
+ describe "#incomplete_address?" do
9
+ subject { TestProxy.incomplete_address?(address) }
10
+
11
+ context "with a missing city" do
12
+ let(:address) { build :address, city: nil }
13
+ it { is_expected.to eq(true) }
14
+ end
15
+
16
+ context "with a missing address1" do
17
+ let(:address) { build :address, address1: nil }
18
+ it { is_expected.to eq(true) }
19
+ end
20
+
21
+ context "with a missing zipcode" do
22
+ let(:address) { build :address, zipcode: nil }
23
+ it { is_expected.to eq(true) }
24
+ end
25
+
26
+ context "with a missing state in CA" do
27
+ let(:address) { build :address, country_iso_code: "CA" }
28
+
29
+ before { address.state = nil }
30
+
31
+ it { is_expected.to eq(true) }
32
+ end
33
+
34
+ context "with a missing state in US" do
35
+ let(:address) { build :address, country_iso_code: "US" }
36
+
37
+ before { address.state = nil }
38
+
39
+ it { is_expected.to eq(true) }
40
+ end
41
+
42
+ context "with a missing state in DE" do
43
+ let(:address) { build :address, country_iso_code: "DE", state: nil }
44
+ it { is_expected.to eq(false) }
45
+ end
46
+ end
47
+
48
+ describe "#state_required?" do
49
+ subject { TestProxy.state_required?(country) }
50
+
51
+ context "when the address' country is Canada" do
52
+ let(:country) { Spree::Country.new(iso: "CA") }
53
+ it { is_expected.to eq(true) }
54
+ end
55
+
56
+ context "when the address' country is the USA" do
57
+ let(:country) { Spree::Country.new(iso: "US") }
58
+ it { is_expected.to eq(true) }
59
+ end
60
+
61
+ context "when the address' country is neither Canada nor the USA" do
62
+ let(:country) { Spree::Country.new(iso: "FR") }
63
+ it { is_expected.to eq(false) }
64
+ end
65
+ end
66
+
67
+ describe "#taxable_address?" do
68
+ subject { TestProxy.taxable_address?(address) }
69
+
70
+ let(:configuration_class) { double }
71
+
72
+ before do
73
+ allow(SuperGood::SolidusTaxjar)
74
+ .to receive(:taxable_address_check)
75
+ .and_return(configuration_class)
76
+ allow(configuration_class).to receive(:call)
77
+ .and_return(taxable_address)
78
+ end
79
+
80
+ context "when taxable address check returns false" do
81
+ let(:taxable_address) { false }
82
+ let(:address) do
83
+ create :address, name: "Canada", country_iso_code: "CA"
84
+ end
85
+
86
+ it { is_expected.to be_falsey }
87
+ end
88
+
89
+ context "when taxable address check returns true" do
90
+ let(:taxable_address) { true }
91
+
92
+ context "with non-US address" do
93
+ let(:address) do
94
+ create :address, name: "Canada", country_iso_code: "CA"
95
+ end
96
+
97
+ it { is_expected.to be_truthy }
98
+ end
99
+
100
+ context "with US address", :vcr do
101
+ let(:usa) { create :country, iso: "US", name: "United States" }
102
+
103
+ # This test expects a TaxJar account to have nexus in California.
104
+ #
105
+ context "when the address is within a nexus region" do
106
+ let(:address) {
107
+ create :address,
108
+ state: create(:state, abbr: "CA", country: usa, name: "Cali!"),
109
+ country: usa,
110
+ zipcode: "94704"
111
+ }
112
+
113
+ it { is_expected.to eq true }
114
+ end
115
+
116
+ # This test expects a TaxJar account to *not* have nexus in Alabama.
117
+ #
118
+ context "when the address is not within a nexus region" do
119
+ let(:address) {
120
+ create :address,
121
+ state: create(:state, abbr: "AL", country: usa, name: "Alabama"),
122
+ country: usa,
123
+ zipcode: "35006"
124
+ }
125
+
126
+ it { is_expected.to eq false }
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
@@ -5,9 +5,26 @@ RSpec.describe SuperGood::SolidusTaxjar::DiscountCalculator do
5
5
  subject { calculator.discount }
6
6
 
7
7
  let(:calculator) { described_class.new line_item }
8
+ let(:line_item) { create :line_item }
9
+ let!(:order) { create :completed_order_with_promotion, promotion: promotion_with_adjustment, line_items: [line_item] }
8
10
 
9
- let(:line_item) { ::Spree::LineItem.new(promo_total: 12.34) }
11
+ let(:cancelation_adjustment_amount) { -8 }
12
+ let(:promotion_adjustment_amount) { -2 }
13
+ let(:promotion_with_adjustment) { create :promotion_with_item_adjustment, adjustment_rate: promotion_adjustment_amount }
14
+ let!(:unit_cancellation_adjustment) { create :adjustment, order: order, adjustable: line_item, amount: cancelation_adjustment_amount, source_type: "Spree::UnitCancel" }
10
15
 
11
- it { is_expected.to eq(-12.34) }
16
+ let!(:tax_adjustment) { create :tax_adjustment, order: order, adjustable: line_item, amount: 2.50 }
17
+
18
+ it "sums the total of all non-tax adjustments" do
19
+ expect(subject).to eq(-1 * (cancelation_adjustment_amount + promotion_adjustment_amount))
20
+ end
21
+
22
+ context "a non-eligible adjustment exists" do
23
+ let!(:unit_cancellation_adjustment) { create :adjustment, order: order, adjustable: line_item, eligible: false, amount: cancelation_adjustment_amount, source_type: "Spree::UnitCancel" }
24
+
25
+ it "only sums eligible adjustments" do
26
+ expect(subject).to eq(-1 * promotion_adjustment_amount)
27
+ end
28
+ end
12
29
  end
13
30
  end
@@ -0,0 +1,194 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe SuperGood::SolidusTaxjar::Reportable do
4
+ class ReportableTestClass
5
+ include SuperGood::SolidusTaxjar::Reportable
6
+
7
+ def initialize(order)
8
+ @order = order
9
+ end
10
+
11
+ def test_with_reportable
12
+ with_reportable(@order) do
13
+ return true
14
+ end
15
+ false
16
+ end
17
+
18
+ def test_with_replaceable
19
+ with_replaceable(@order) do
20
+ return true
21
+ end
22
+ false
23
+ end
24
+ end
25
+
26
+ let(:reportable_test_class) { ReportableTestClass.new(order) }
27
+
28
+ describe "#with_reportable" do
29
+ subject { reportable_test_class.test_with_reportable }
30
+
31
+ let!(:taxjar_configuration) { create(:taxjar_configuration, preferred_reporting_enabled_at_integer: nil) }
32
+
33
+ let(:order) { create(:order) }
34
+
35
+ it { is_expected.to be_falsey }
36
+
37
+ context "when reporting is enabled" do
38
+ let!(:taxjar_configuration) { create(:taxjar_configuration, preferred_reporting_enabled_at_integer: 1.hour.ago) }
39
+
40
+ it { is_expected.to be_falsey }
41
+
42
+ context "is completed" do
43
+ let(:order) { create(:completed_order_with_totals) }
44
+
45
+ it { is_expected.to be_falsey }
46
+
47
+ context "is shipped" do
48
+ let(:order) { create(:shipped_order) }
49
+
50
+ it { is_expected.to be_truthy }
51
+
52
+ context "the order is not paid" do
53
+ before do
54
+ order.update_columns(payment_state: :balance_due)
55
+ end
56
+
57
+ it { is_expected.to be_falsey }
58
+ end
59
+
60
+ context "when the order has a failed transaction sync log and no order transactions" do
61
+ before do
62
+ create :transaction_sync_log, :error, order: order
63
+ end
64
+
65
+ it { is_expected.to be_truthy }
66
+ end
67
+
68
+ context "when the order has a failed transaction sync log, and an existing order transaction" do
69
+ before do
70
+ create :transaction_sync_log, :error, order: order
71
+ create :taxjar_order_transaction, order: order
72
+ end
73
+
74
+ it { is_expected.to be_falsey }
75
+ end
76
+
77
+ context "when the order was completed before reporting was enabled" do
78
+ before do
79
+ allow(SuperGood::SolidusTaxjar.exception_handler)
80
+ .to receive(:call)
81
+
82
+ order.update_columns(completed_at: 2.days.ago)
83
+ end
84
+
85
+ it { is_expected.to be_falsey }
86
+
87
+ it "creates a sync log with an error" do
88
+ expect { subject }
89
+ .to change { order.taxjar_transaction_sync_logs.count }
90
+ .from(0)
91
+ .to(1)
92
+
93
+ expect(order.taxjar_transaction_sync_logs.last).to have_attributes(
94
+ status: "error",
95
+ error_message: "Order cannot be synced because it was completed before TaxJar reporting was enabled"
96
+ )
97
+ end
98
+
99
+ it "calls the solidus taxjar exception handler with the error" do
100
+ subject
101
+
102
+ expect(SuperGood::SolidusTaxjar.exception_handler)
103
+ .to have_received(:call)
104
+ .with(RuntimeError.new("Order cannot be synced because it was completed before TaxJar reporting was enabled"))
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ describe "#with_replaceable" do
113
+ subject { reportable_test_class.test_with_replaceable }
114
+
115
+ let!(:taxjar_configuration) { create(:taxjar_configuration, preferred_reporting_enabled_at_integer: nil) }
116
+
117
+ let(:order) { create(:order) }
118
+
119
+ it { is_expected.to be_falsey }
120
+
121
+ context "when reporting is enabled and the order is completed and shipped" do
122
+ let!(:taxjar_configuration) { create(:taxjar_configuration, preferred_reporting_enabled_at_integer: 1.hour.ago) }
123
+ let(:order) do
124
+ order = create(:completed_order_with_pending_payment)
125
+ order.update_columns(shipment_state: :shipped)
126
+ order
127
+ end
128
+ let(:last_transaction_amount) { order.payment_total - order.additional_tax_total }
129
+ let(:dummy_api) { instance_double ::SuperGood::SolidusTaxjar::Api }
130
+
131
+ before do
132
+ allow(dummy_api)
133
+ .to receive(:show_latest_transaction_for)
134
+ .and_return(double(amount: last_transaction_amount))
135
+ allow(SuperGood::SolidusTaxjar)
136
+ .to receive(:api)
137
+ .and_return(dummy_api)
138
+ end
139
+
140
+ it { is_expected.to be_falsey }
141
+
142
+ context "when the order has a previous taxjar transaction" do
143
+ before do
144
+ create(:taxjar_order_transaction, order: order)
145
+ end
146
+
147
+ it { is_expected.to be_falsey }
148
+
149
+ context "when the order is paid" do
150
+ let(:order) { create :shipped_order }
151
+
152
+ it { is_expected.to be_falsey }
153
+
154
+ context "when the order's amount has changed" do
155
+ let(:last_transaction_amount) { order.payment_total - 12 }
156
+
157
+ it { is_expected.to be_truthy }
158
+
159
+ context "when the order was completed before reporting was enabled" do
160
+ before do
161
+ allow(SuperGood::SolidusTaxjar.exception_handler)
162
+ .to receive(:call)
163
+
164
+ order.update_columns(completed_at: 2.days.ago)
165
+ end
166
+
167
+ it { is_expected.to be_falsey }
168
+
169
+ it "creates a sync log with an error" do
170
+ expect { subject }
171
+ .to change { order.taxjar_transaction_sync_logs.count }
172
+ .from(0)
173
+ .to(1)
174
+
175
+ expect(order.taxjar_transaction_sync_logs.last).to have_attributes(
176
+ status: "error",
177
+ error_message: "Order cannot be synced because it was completed before TaxJar reporting was enabled"
178
+ )
179
+ end
180
+
181
+ it "calls the solidus taxjar exception handler with the error" do
182
+ subject
183
+
184
+ expect(SuperGood::SolidusTaxjar.exception_handler)
185
+ .to have_received(:call)
186
+ .with(RuntimeError.new("Order cannot be synced because it was completed before TaxJar reporting was enabled"))
187
+ end
188
+ end
189
+ end
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end