solidus_avatax 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c3f13da28a6ec0b6a5dedfc5db7f298ae881ba1c
4
- data.tar.gz: bbf4d9d57e5b13968824d4c9d8520c135fdb9e3e
3
+ metadata.gz: 4525b6e8313606fbd57767df4d08f36d55fa200b
4
+ data.tar.gz: 51e8687c4913ed18239ec2d4b49c69fb52a18d82
5
5
  SHA512:
6
- metadata.gz: a79dfd4cfd4739b2c4de0bb977bbddecc2dd95da488b22f9c45c1dbf9616826d28063db60cc43b51526384cece47d486f5a0ed9d71bb04fd484fdfa21cf1fce2
7
- data.tar.gz: 6da751a3e486acca13773199cfef7eb2d37774b1a1a4887838be4f115a55a27ad10a6e4b1b555d875a3f8b3ecdd88ff7e3956ea7c1a8e76c184aae536f7d1727
6
+ metadata.gz: b344c75e4567fb07469a05caa6956a9c4df9ba79f60226a3c87ef7582636abced2c66d47e2214421691886e63f52e662ada8b84c5dcac2bb1bd650128c040ef3
7
+ data.tar.gz: c50aa1946c3e50fcb4d252edfdbc54384445129c0554cc91f393aee18c6bb77ec4ab43353aef221f5b1bb57e56e663644a3bba334718d6367c05f3952c45fe97
@@ -0,0 +1,14 @@
1
+ sudo: false
2
+ cache: bundler
3
+ language: ruby
4
+ env:
5
+ matrix:
6
+ - SOLIDUS_BRANCH=v1.1 DB=mysql
7
+ - SOLIDUS_BRANCH=v1.2 DB=mysql
8
+ - SOLIDUS_BRANCH=v1.1 DB=postgres
9
+ - SOLIDUS_BRANCH=v1.2 DB=postgres
10
+ script:
11
+ - bundle exec rake test_app
12
+ - bundle exec rspec
13
+ rvm:
14
+ - 2.1.8
data/Gemfile CHANGED
@@ -1,8 +1,12 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- gem "solidus", github: "solidusio/solidus", branch: "master"
3
+ branch = ENV.fetch('SOLIDUS_BRANCH', 'v1.2')
4
+ gem "solidus", github: "solidusio/solidus", branch: branch
4
5
  gem "solidus_auth_devise", "~> 1.0"
5
6
 
7
+ gem 'pg'
8
+ gem 'mysql2'
9
+
6
10
  group :development, :test do
7
11
  gem "pry-rails"
8
12
  gem 'pry-byebug'
data/README.md CHANGED
@@ -22,6 +22,22 @@ rails g solidus_avatax:install
22
22
  Configuration
23
23
  -------------
24
24
 
25
+ #### Disabling Avatax and Avatax API Timeouts
26
+
27
+ In case of service problems or outages on Avatax's end, you can disable Avatax
28
+ or change the API timeout. These values are stored in the database so that they
29
+ can be applied instantly and without restarting your application. To change the
30
+ values create a new SpreeAvatax::Config. The default values are:
31
+
32
+ ```ruby
33
+ SpreeAvatax::Config.create!(enabled: true, timeout: SpreeAvatax::Config::DEFAULT_TIMEOUT)
34
+ ```
35
+
36
+ This is an append-only table and solidus_avatax will read these config values
37
+ from the last record (by id).
38
+
39
+ #### Short Ships
40
+
25
41
  If you want to notify Avatax about short ships you should configure the
26
42
  following:
27
43
 
@@ -0,0 +1,38 @@
1
+ module SpreeAvatax
2
+ class Config < Spree::Base
3
+ DEFAULT_TIMEOUT = 20
4
+
5
+ class << self
6
+ attr_accessor :username
7
+ attr_accessor :password
8
+ attr_accessor :company_code
9
+ attr_accessor :service_url
10
+ # These error handlers should be objects that respond to "call" and accept an order and an
11
+ # exception as arguments. This allows you to ignore certain errors or handle them in
12
+ # specific ways.
13
+ attr_accessor :sales_invoice_generate_error_handler
14
+ attr_accessor :sales_invoice_commit_error_handler
15
+ attr_accessor :sales_invoice_cancel_error_handler
16
+
17
+ # These configurations are stored in the database so that they can be
18
+ # updated immediately and synchronously across all servers in the event of
19
+ # an outage, without a redeploy or restart.
20
+ def timeout
21
+ (config = active) ? config.timeout : DEFAULT_TIMEOUT
22
+ end
23
+
24
+ def enabled
25
+ (config = active) ? config.enabled : true
26
+ end
27
+
28
+ private
29
+
30
+ def active
31
+ order(:id).last
32
+ end
33
+ end
34
+
35
+ validates :enabled, inclusion: {in: [true, false]}
36
+ validates :timeout, presence: true
37
+ end
38
+ end
@@ -31,6 +31,11 @@ class SpreeAvatax::ReturnInvoice < ActiveRecord::Base
31
31
  # After the reimbursement completes the ".finalize" method will get called and we'll commit the
32
32
  # return invoice.
33
33
  def generate(reimbursement)
34
+ if !SpreeAvatax::Config.enabled
35
+ logger.info("Avatax disabled. Skipping ReturnInvoice.generate for reimbursement #{reimbursement.number}")
36
+ return
37
+ end
38
+
34
39
  success_result = get_tax(reimbursement)
35
40
 
36
41
  if reimbursement.return_invoice
@@ -74,6 +79,11 @@ class SpreeAvatax::ReturnInvoice < ActiveRecord::Base
74
79
  # On failure it will raise.
75
80
  # On success it markes the invoice as committed.
76
81
  def finalize(reimbursement)
82
+ if !SpreeAvatax::Config.enabled
83
+ logger.info("Avatax disabled. Skipping ReturnInvoice.finalize for reimbursement #{reimbursement.number}")
84
+ return
85
+ end
86
+
77
87
  post_tax(reimbursement.return_invoice)
78
88
 
79
89
  reimbursement.return_invoice.update!(committed: true)
@@ -87,7 +97,7 @@ class SpreeAvatax::ReturnInvoice < ActiveRecord::Base
87
97
  avatax_logger.info "AVATAX_REQUEST context=get_tax reimbursement_id=#{reimbursement.id}"
88
98
  avatax_logger.debug params.to_json
89
99
 
90
- result = tax_svc.gettax(params)
100
+ result = SpreeAvatax::Shared.get_tax(params)
91
101
  require_success!(result, reimbursement, 'get_tax')
92
102
 
93
103
  result
@@ -99,7 +109,7 @@ class SpreeAvatax::ReturnInvoice < ActiveRecord::Base
99
109
  avatax_logger.info "AVATAX_REQUEST context=post_tax reimbursement_id=#{return_invoice.reimbursement.id} return_invoice_id=#{return_invoice.id}"
100
110
  avatax_logger.debug params.to_json
101
111
 
102
- result = tax_svc.posttax(params)
112
+ result = SpreeAvatax::Shared.post_tax(params)
103
113
  require_success!(result, return_invoice.reimbursement, 'post_tax')
104
114
 
105
115
  result
@@ -184,14 +194,5 @@ class SpreeAvatax::ReturnInvoice < ActiveRecord::Base
184
194
  totaltax: return_invoice.additional_tax_total,
185
195
  }
186
196
  end
187
-
188
- def tax_svc
189
- @tax_svc ||= AvaTax::TaxService.new({
190
- username: SpreeAvatax::Config.username,
191
- password: SpreeAvatax::Config.password,
192
- service_url: SpreeAvatax::Config.service_url,
193
- clientname: 'Spree::Avatax',
194
- })
195
- end
196
197
  end
197
198
  end
@@ -23,6 +23,11 @@ class SpreeAvatax::SalesInvoice < ActiveRecord::Base
23
23
  def generate(order)
24
24
  bench_start = Time.now
25
25
 
26
+ if !SpreeAvatax::Config.enabled
27
+ logger.info("Avatax disabled. Skipping SalesInvoice.generate for order #{order.number}")
28
+ return
29
+ end
30
+
26
31
  return if order.completed? || !SpreeAvatax::Shared.taxable_order?(order)
27
32
 
28
33
  taxable_records = order.line_items + order.shipments
@@ -42,6 +47,8 @@ class SpreeAvatax::SalesInvoice < ActiveRecord::Base
42
47
  end
43
48
  end
44
49
 
50
+ SpreeAvatax::SalesShared.update_taxes(order, tax_line_data)
51
+
45
52
  sales_invoice = order.create_avatax_sales_invoice!({
46
53
  transaction_id: result[:transaction_id],
47
54
  doc_id: result[:doc_id],
@@ -51,8 +58,6 @@ class SpreeAvatax::SalesInvoice < ActiveRecord::Base
51
58
  additional_tax_total: result[:total_tax],
52
59
  })
53
60
 
54
- SpreeAvatax::SalesShared.update_taxes(order, tax_line_data)
55
-
56
61
  sales_invoice
57
62
  rescue Exception => e
58
63
  if SpreeAvatax::Config.sales_invoice_generate_error_handler
@@ -66,6 +71,11 @@ class SpreeAvatax::SalesInvoice < ActiveRecord::Base
66
71
  end
67
72
 
68
73
  def commit(order)
74
+ if !SpreeAvatax::Config.enabled
75
+ logger.info("Avatax disabled. Skipping SalesInvoice.commit for order #{order.number}")
76
+ return
77
+ end
78
+
69
79
  return if !SpreeAvatax::Shared.taxable_order?(order)
70
80
 
71
81
  raise CommitInvoiceNotFound.new("No invoice for order #{order.number}") if order.avatax_sales_invoice.nil?
@@ -84,6 +94,11 @@ class SpreeAvatax::SalesInvoice < ActiveRecord::Base
84
94
  end
85
95
 
86
96
  def cancel(order)
97
+ if !SpreeAvatax::Config.enabled
98
+ logger.info("Avatax disabled. Skipping SalesInvoice.cancel for order #{order.number}")
99
+ return
100
+ end
101
+
87
102
  return if order.avatax_sales_invoice.nil?
88
103
 
89
104
  result = cancel_tax(order.avatax_sales_invoice)
@@ -108,7 +123,7 @@ class SpreeAvatax::SalesInvoice < ActiveRecord::Base
108
123
  logger.info "[avatax] posttax sales_invoice=#{sales_invoice.id} order=#{sales_invoice.order_id}"
109
124
  logger.debug { "[avatax] params: #{params.to_json}" }
110
125
 
111
- response = SpreeAvatax::Shared.tax_svc.posttax(params)
126
+ response = SpreeAvatax::Shared.post_tax(params)
112
127
  SpreeAvatax::Shared.require_success!(response)
113
128
 
114
129
  response
@@ -120,8 +135,7 @@ class SpreeAvatax::SalesInvoice < ActiveRecord::Base
120
135
  logger.info "[avatax] canceltax sales_invoice=#{sales_invoice.id}"
121
136
  logger.debug { "[avatax] params: #{params.to_json}" }
122
137
 
123
- response = SpreeAvatax::Shared.tax_svc.canceltax(params)
124
-
138
+ response = SpreeAvatax::Shared.cancel_tax(params)
125
139
  SpreeAvatax::Shared.require_success!(response)
126
140
 
127
141
  response
@@ -18,7 +18,8 @@ module SpreeAvatax::SalesShared
18
18
  logger.info "[avatax] gettax order=#{order.id} doc_type=#{doc_type}"
19
19
  logger.debug { "[avatax] params: #{params.to_json}" }
20
20
 
21
- response = SpreeAvatax::Shared.tax_svc.gettax(params)
21
+ response = SpreeAvatax::Shared.get_tax(params)
22
+
22
23
  SpreeAvatax::Shared.require_success!(response)
23
24
 
24
25
  response
@@ -30,7 +31,7 @@ module SpreeAvatax::SalesShared
30
31
  tax_line_data.each do |data|
31
32
  record, tax_line = data[:record], data[:tax_line]
32
33
 
33
- record.update_column(:pre_tax_amount, record.discounted_amount)
34
+ record.update_column(:pre_tax_amount, record.discounted_amount.round(2))
34
35
 
35
36
  tax = BigDecimal.new(tax_line[:tax]).abs
36
37
 
@@ -72,7 +73,7 @@ module SpreeAvatax::SalesShared
72
73
  if data[avatax_id]
73
74
  data[avatax_id][:tax_line] = tax_line
74
75
  else
75
- raise InvalidApiResponse.new("Couldn't find #{avatax_id.inspect}")
76
+ raise InvalidApiResponse.new("Couldn't find #{avatax_id.inspect} from avatax response in known ids #{data.keys.inspect}")
76
77
  end
77
78
  end
78
79
 
@@ -98,19 +99,32 @@ module SpreeAvatax::SalesShared
98
99
  def reset_tax_attributes(order)
99
100
  return if order.completed?
100
101
 
102
+ # Delete the avatax_sales_invoice to avoid accidentally committing it
103
+ # later.
104
+ if invoice = order.avatax_sales_invoice
105
+ if invoice.committed_at
106
+ raise SpreeAvatax::SalesInvoice::AlreadyCommittedError.new(
107
+ "Tried to clear tax attributes for already-committed order #{order.number}"
108
+ )
109
+ else
110
+ invoice.destroy!
111
+ end
112
+ end
113
+
101
114
  destroyed_adjustments = order.all_adjustments.tax.destroy_all
102
115
  return if destroyed_adjustments.empty?
103
116
 
104
- order.line_items.each do |line_item|
105
- line_item.update_attributes!({
117
+ taxable_records = order.line_items + order.shipments
118
+ taxable_records.each do |taxable_record|
119
+ taxable_record.update_attributes!({
106
120
  additional_tax_total: 0,
107
121
  adjustment_total: 0,
108
- pre_tax_amount: 0,
122
+ pre_tax_amount: taxable_record.discounted_amount.round(2),
109
123
  included_tax_total: 0,
110
124
  })
111
125
 
112
- Spree::ItemAdjustments.new(line_item).update
113
- line_item.save!
126
+ Spree::ItemAdjustments.new(taxable_record).update
127
+ taxable_record.save!
114
128
  end
115
129
 
116
130
  order.update_attributes!({
@@ -28,6 +28,18 @@ module SpreeAvatax::Shared
28
28
  order.line_items.present? && order.ship_address.present?
29
29
  end
30
30
 
31
+ def get_tax(params)
32
+ call_tax_svc_with_timeout(:gettax, params)
33
+ end
34
+
35
+ def post_tax(params)
36
+ call_tax_svc_with_timeout(:posttax, params)
37
+ end
38
+
39
+ def cancel_tax(params)
40
+ call_tax_svc_with_timeout(:canceltax, params)
41
+ end
42
+
31
43
  def tax_svc
32
44
  @tax_svc ||= AvaTax::TaxService.new({
33
45
  username: SpreeAvatax::Config.username,
@@ -37,6 +49,13 @@ module SpreeAvatax::Shared
37
49
  })
38
50
  end
39
51
 
52
+ # We looked at the code in the AvaTax gem and using timeout here seems safe.
53
+ def call_tax_svc_with_timeout(method, *args)
54
+ Timeout.timeout(SpreeAvatax::Config.timeout, SpreeAvatax::AvataxTimeout) do
55
+ tax_svc.public_send(method, *args)
56
+ end
57
+ end
58
+
40
59
  def require_success!(response)
41
60
  if response[:result_code] == 'Success'
42
61
  logger.info "[avatax] response - result=success doc_id=#{response[:doc_id]} doc_code=#{response[:doc_code]} transaction_id=#{response[:transaction_id]}"
@@ -22,6 +22,11 @@ class SpreeAvatax::ShortShipReturnInvoice < ActiveRecord::Base
22
22
  #
23
23
  # On failure it will raise.
24
24
  def generate(unit_cancels:)
25
+ if !SpreeAvatax::Config.enabled
26
+ logger.info("Avatax disabled. Skipping ShortShipReturnInvoice.generate for unit_cancels #{unit_cancels.map(&:id)}")
27
+ return
28
+ end
29
+
25
30
  inventory_units = unit_cancels.map(&:inventory_unit)
26
31
 
27
32
  order_ids = inventory_units.map(&:order_id).uniq
@@ -48,7 +53,7 @@ class SpreeAvatax::ShortShipReturnInvoice < ActiveRecord::Base
48
53
  logger.info("[avatax] gettax unit_cancel_ids=#{unit_cancels.map(&:id)} doc_type=#{DOC_TYPE}")
49
54
  logger.debug("[avatax] params: " + params.to_json)
50
55
 
51
- response = SpreeAvatax::Shared.tax_svc.gettax(params)
56
+ response = SpreeAvatax::Shared.get_tax(params)
52
57
  SpreeAvatax::Shared.require_success!(response)
53
58
 
54
59
  response
@@ -0,0 +1,10 @@
1
+ class AddSpreeAvataxConfigs < ActiveRecord::Migration
2
+ def change
3
+ create_table 'spree_avatax_configs' do |t|
4
+ t.boolean 'enabled', null: false
5
+ t.float 'timeout', null: false
6
+
7
+ t.datetime 'created_at', null: false
8
+ end
9
+ end
10
+ end
@@ -1,4 +1,7 @@
1
1
  require 'spree_core'
2
- require "spree_avatax/config"
3
2
  require 'spree_avatax/engine'
4
3
  require 'avatax_taxservice'
4
+
5
+ module SpreeAvatax
6
+ class AvataxTimeout < Timeout::Error; end
7
+ end
@@ -22,4 +22,9 @@ FactoryGirl.define do
22
22
  pre_tax_total { reimbursement.return_items.sum(:pre_tax_amount) }
23
23
  additional_tax_total { reimbursement.return_items.sum(:additional_tax_total) }
24
24
  end
25
+
26
+ factory :avatax_config, class: SpreeAvatax::Config do
27
+ enabled true
28
+ timeout SpreeAvatax::Config::DEFAULT_TIMEOUT
29
+ end
25
30
  end
@@ -29,13 +29,6 @@ namespace :spree_avatax do
29
29
 
30
30
  # PREP TO ITERATE OVER ORDERS
31
31
 
32
- tax_svc = AvaTax::TaxService.new({
33
- username: SpreeAvatax::Config.username,
34
- password: SpreeAvatax::Config.password,
35
- service_url: SpreeAvatax::Config.service_url,
36
- clientname: 'Spree::Avatax',
37
- })
38
-
39
32
  handle_result_errors = ->(result, order, request_method) do
40
33
  puts
41
34
  puts "** Error on order id=#{order.id} number=#{order.number} **"
@@ -63,7 +56,7 @@ namespace :spree_avatax do
63
56
  detaillevel: 'Tax',
64
57
  }
65
58
 
66
- history_result = tax_svc.gettaxhistory(history_request)
59
+ history_result = SpreeAvatax::Shared.tax_svc.gettaxhistory(history_request)
67
60
 
68
61
  if history_result[:result_code] != 'Success'
69
62
  error_count += 1
@@ -91,7 +84,7 @@ namespace :spree_avatax do
91
84
  totaltax: history_result[:get_tax_result][:total_tax],
92
85
  }
93
86
 
94
- post_result = tax_svc.posttax(post_request)
87
+ post_result = SpreeAvatax::Shared.tax_svc.posttax(post_request)
95
88
 
96
89
  if post_result[:result_code] != 'Success'
97
90
  error_count += 1
@@ -2,7 +2,7 @@
2
2
  Gem::Specification.new do |s|
3
3
  s.platform = Gem::Platform::RUBY
4
4
  s.name = "solidus_avatax"
5
- s.version = "1.0.0"
5
+ s.version = "1.1.0"
6
6
  s.summary = "Avatax extension for Solidus"
7
7
  s.description = "Solidus extension to retrieve tax rates via Avalara's SOAP API."
8
8
  s.required_ruby_version = ">= 2.1"
@@ -17,13 +17,12 @@ Gem::Specification.new do |s|
17
17
  s.require_path = "lib"
18
18
  s.requirements << "none"
19
19
 
20
- s.add_dependency "solidus_core", "~> 1.1.0.pre"
20
+ s.add_dependency "solidus_core", ">= 1.1.0.pre", "< 1.3"
21
21
  s.add_dependency "hashie", "~> 2.l.5"
22
22
  s.add_dependency "multi_json"
23
23
  s.add_dependency "Avatax_TaxService", "~> 2.0.0"
24
24
 
25
25
  s.add_development_dependency "rspec-rails","~> 3.2"
26
- s.add_development_dependency "simplecov"
27
26
  s.add_development_dependency "sqlite3"
28
27
  s.add_development_dependency "sass-rails"
29
28
  s.add_development_dependency "coffee-rails"
@@ -54,12 +54,24 @@ RSpec.describe "Taxes with Store Credits" do
54
54
  fill_in "Phone", with: "(555) 555-5555"
55
55
  end
56
56
  click_on "Save and Continue"
57
-
58
57
  end
59
58
 
60
59
  it "adjusts the credits to cover taxes" do
61
60
  # Use a cassette so that we don't hit the Avatax API all of the time.
62
61
  VCR.use_cassette("taxes_with_store_credits") do
62
+ expect(SpreeAvatax::SalesShared).to(
63
+ receive(:avatax_id).
64
+ with(an_instance_of(Spree::LineItem)).
65
+ at_least(:once).
66
+ and_return('Spree::LineItem-1')
67
+ )
68
+ expect(SpreeAvatax::SalesShared).to(
69
+ receive(:avatax_id).
70
+ with(an_instance_of(Spree::Shipment)).
71
+ at_least(:once).
72
+ and_return('Spree::Shipment-1')
73
+ )
74
+
63
75
  click_on "Save and Continue"
64
76
  end
65
77
 
@@ -5,6 +5,7 @@ describe "Tax Calculation" do
5
5
  let(:address) { create(:address, address1: "35 Crosby St", city: "New York", zipcode: 10013) }
6
6
  let(:line_item_1) { order.line_items.first }
7
7
  let(:line_item_2) { order.line_items.last }
8
+ let(:shipment) { order.shipments.first }
8
9
 
9
10
  before do
10
11
  # Set up Avatax (just in case we don't have a cassette)
@@ -14,6 +15,25 @@ describe "Tax Calculation" do
14
15
  SpreeAvatax::Config.company_code = ENV["AVATAX_COMPANY_CODE"]
15
16
 
16
17
  order.line_items.first.product.tax_category.tax_rates << Spree::TaxRate.first
18
+
19
+ expect(SpreeAvatax::SalesShared).to(
20
+ receive(:avatax_id).
21
+ with(line_item_1).
22
+ at_least(:once).
23
+ and_return('Spree::LineItem-1')
24
+ )
25
+ expect(SpreeAvatax::SalesShared).to(
26
+ receive(:avatax_id).
27
+ with(line_item_2).
28
+ at_least(:once).
29
+ and_return('Spree::LineItem-2')
30
+ )
31
+ expect(SpreeAvatax::SalesShared).to(
32
+ receive(:avatax_id).
33
+ with(shipment).
34
+ at_least(:once).
35
+ and_return('Spree::Shipment-1')
36
+ )
17
37
  end
18
38
 
19
39
  context "without discounts" do
@@ -56,8 +56,8 @@ describe SpreeAvatax::ReturnInvoice do
56
56
  BigDecimal.new(gettax_response_return_item_tax_line[:tax]).abs
57
57
  end
58
58
 
59
- before do
60
- expect(SpreeAvatax::ReturnInvoice.send(:tax_svc))
59
+ let!(:tax_svc_expectation) do
60
+ expect(SpreeAvatax::Shared.tax_svc)
61
61
  .to receive(:gettax)
62
62
  .with(expected_gettax_params)
63
63
  .and_return(gettax_response)
@@ -150,6 +150,17 @@ describe SpreeAvatax::ReturnInvoice do
150
150
  subject
151
151
  end
152
152
  end
153
+
154
+ context 'when avatax is disabled' do
155
+ let!(:config) { create(:avatax_config, enabled: false) }
156
+ let!(:tax_svc_expectation) { expect(SpreeAvatax::Shared).to_not receive(:tax_svc) }
157
+
158
+ it 'does nothing' do
159
+ expect {
160
+ subject
161
+ }.to_not change { SpreeAvatax::ReturnInvoice.count }
162
+ end
163
+ end
153
164
  end
154
165
 
155
166
  describe '.finalize' do
@@ -170,8 +181,8 @@ describe SpreeAvatax::ReturnInvoice do
170
181
  }
171
182
  end
172
183
 
173
- before do
174
- expect(SpreeAvatax::ReturnInvoice.send(:tax_svc))
184
+ let!(:tax_svc_expectation) do
185
+ expect(SpreeAvatax::Shared.tax_svc)
175
186
  .to receive(:posttax)
176
187
  .with(expected_posttax_params)
177
188
  .and_return(
@@ -188,6 +199,16 @@ describe SpreeAvatax::ReturnInvoice do
188
199
  subject
189
200
  }.to change { return_invoice.reload.committed? }.from(false).to(true)
190
201
  end
202
+
203
+ context 'when avatax is disabled' do
204
+ let!(:config) { create(:avatax_config, enabled: false) }
205
+ let!(:tax_svc_expectation) { expect(SpreeAvatax::Shared).to_not receive(:tax_svc) }
206
+
207
+ it 'does nothing' do
208
+ subject
209
+ expect(return_invoice.reload.committed?).to be_falsey
210
+ end
211
+ end
191
212
  end
192
213
 
193
214
  end
@@ -93,7 +93,7 @@ describe SpreeAvatax::SalesInvoice do
93
93
  BigDecimal.new(gettax_response_shipment_tax_line[:tax]).abs
94
94
  end
95
95
 
96
- let!(:gettax_stub) do
96
+ let!(:tax_svc_expectation) do
97
97
  expect(SpreeAvatax::Shared.tax_svc)
98
98
  .to receive(:gettax)
99
99
  .with(expected_gettax_params)
@@ -180,7 +180,7 @@ describe SpreeAvatax::SalesInvoice do
180
180
 
181
181
  context 'when an error occurs' do
182
182
  let(:error) { StandardError.new('just testing') }
183
- let!(:gettax_stub) { }
183
+ let!(:tax_svc_expectation) { }
184
184
  let(:order) do
185
185
  create(:order_with_line_items,
186
186
  line_items_count: 2,
@@ -200,7 +200,7 @@ describe SpreeAvatax::SalesInvoice do
200
200
  .to receive(:get_tax)
201
201
  .and_raise(error)
202
202
 
203
- order.line_items.update_all(pre_tax_amount: nil)
203
+ order.line_items.update_all(pre_tax_amount: 0)
204
204
  order.reload
205
205
  end
206
206
 
@@ -288,7 +288,7 @@ describe SpreeAvatax::SalesInvoice do
288
288
  context 'when the order is not taxable' do
289
289
  let(:order) { create(:order_with_line_items, ship_address: nil, line_items_count: 1) }
290
290
 
291
- let!(:gettax_stub) { }
291
+ let!(:tax_svc_expectation) { }
292
292
 
293
293
  it 'does not create a sales invoice' do
294
294
  expect {
@@ -306,7 +306,7 @@ describe SpreeAvatax::SalesInvoice do
306
306
  context 'when the order is already completed' do
307
307
  let(:order) { create(:completed_order_with_totals) }
308
308
 
309
- let!(:gettax_stub) { }
309
+ let!(:tax_svc_expectation) { }
310
310
 
311
311
  it 'does not create a sales invoice' do
312
312
  expect {
@@ -320,6 +320,33 @@ describe SpreeAvatax::SalesInvoice do
320
320
  subject
321
321
  end
322
322
  end
323
+
324
+ context 'when avatax is disabled' do
325
+ let!(:config) { create(:avatax_config, enabled: false) }
326
+ let!(:tax_svc_expectation) { expect(SpreeAvatax::Shared).to_not receive(:tax_svc) }
327
+
328
+ it 'does nothing' do
329
+ expect {
330
+ subject
331
+ }.to_not change { SpreeAvatax::SalesInvoice.count }
332
+ end
333
+ end
334
+
335
+ context 'when an error occurs during tax updating' do
336
+ it 'does not create a SalesInvoice record' do
337
+ error = StandardError.new
338
+
339
+ expect(SpreeAvatax::SalesShared)
340
+ .to receive(:update_taxes)
341
+ .and_raise(error)
342
+
343
+ expect {
344
+ expect { subject }.to raise_error(error)
345
+ }.to_not change {
346
+ SpreeAvatax::SalesInvoice.count
347
+ }
348
+ end
349
+ end
323
350
  end
324
351
 
325
352
  describe '.commit' do
@@ -417,6 +444,16 @@ describe SpreeAvatax::SalesInvoice do
417
444
  end
418
445
  end
419
446
  end
447
+
448
+ context 'when avatax is disabled' do
449
+ let!(:config) { create(:avatax_config, enabled: false) }
450
+ let!(:tax_svc_expectation) { expect(SpreeAvatax::Shared).to_not receive(:tax_svc) }
451
+
452
+ it 'does nothing' do
453
+ subject
454
+ expect(sales_invoice.reload.committed_at?).to be_falsey
455
+ end
456
+ end
420
457
  end
421
458
 
422
459
  describe '.cancel' do
@@ -439,7 +476,7 @@ describe SpreeAvatax::SalesInvoice do
439
476
 
440
477
  let(:canceltax_response) { sales_invoice_canceltax_response }
441
478
 
442
- let!(:canceltax_stub) do
479
+ let!(:tax_svc_expectation) do
443
480
  expect(SpreeAvatax::Shared.tax_svc)
444
481
  .to receive(:canceltax)
445
482
  .with(expected_canceltax_params)
@@ -455,7 +492,7 @@ describe SpreeAvatax::SalesInvoice do
455
492
 
456
493
  context 'when an error occurs' do
457
494
  let(:error) { StandardError.new('just testing') }
458
- let!(:canceltax_stub) { }
495
+ let!(:tax_svc_expectation) { }
459
496
 
460
497
  before do
461
498
  expect(SpreeAvatax::SalesInvoice)
@@ -486,6 +523,16 @@ describe SpreeAvatax::SalesInvoice do
486
523
  end
487
524
  end
488
525
  end
526
+
527
+ context 'when avatax is disabled' do
528
+ let!(:config) { create(:avatax_config, enabled: false) }
529
+ let!(:tax_svc_expectation) { expect(SpreeAvatax::Shared).to_not receive(:tax_svc) }
530
+
531
+ it 'does nothing' do
532
+ subject
533
+ expect(sales_invoice.canceled_at?).to be_falsey
534
+ end
535
+ end
489
536
  end
490
537
  end
491
538
  end
@@ -7,10 +7,19 @@ describe SpreeAvatax::SalesShared do
7
7
  SpreeAvatax::SalesShared.reset_tax_attributes(order)
8
8
  end
9
9
 
10
- let(:order) { create(:order_with_line_items, additional_tax_total: 1, adjustment_total: 1, included_tax_total: 1, line_items_count: 1) }
10
+ let(:order) do
11
+ create(:order_with_line_items,
12
+ line_items_count: 1, # quantity set to 2 below
13
+ line_items_price: 3,
14
+ shipment_cost: 5,
15
+ )
16
+ end
11
17
  let(:line_item) { order.line_items.first }
18
+ let(:shipment) { order.shipments.first }
12
19
 
13
20
  before do
21
+ line_item.update_attributes!(quantity: 2)
22
+
14
23
  line_item.adjustments.eligible.tax.additional.create!({
15
24
  adjustable: line_item,
16
25
  amount: 1.23,
@@ -43,5 +52,34 @@ describe SpreeAvatax::SalesShared do
43
52
  subject
44
53
  expect(line_item.adjustments.tax.count).to eq 0
45
54
  end
55
+
56
+ it 'sets pre_tax_amount to discounted_amount' do
57
+ subject
58
+ expect(line_item.reload.pre_tax_amount).to eq(2 * 3)
59
+ expect(shipment.reload.pre_tax_amount).to eq(5)
60
+ end
61
+
62
+ context 'when a SalesInvoice record is present' do
63
+ let!(:sales_invoice) { create(:avatax_sales_invoice, order: order) }
64
+
65
+ it 'deletes the SalesInvoice record if present' do
66
+ subject
67
+ expect(order.reload.avatax_sales_invoice).to eq(nil)
68
+ end
69
+
70
+ context 'when the SalesInvoice is committed' do
71
+ before do
72
+ sales_invoice.update!(committed_at: Time.now)
73
+ end
74
+
75
+ it 'raises without clearing anything' do
76
+ expect {
77
+ subject
78
+ }.to raise_error(SpreeAvatax::SalesInvoice::AlreadyCommittedError)
79
+
80
+ expect(line_item.adjustments.tax.count).to eq(1)
81
+ end
82
+ end
83
+ end
46
84
  end
47
85
  end
@@ -86,4 +86,58 @@ describe SpreeAvatax::Shared do
86
86
  end
87
87
  end
88
88
  end
89
+
90
+ describe '.get_tax' do
91
+ it 'calls gettax' do
92
+ params = {}
93
+ expect(SpreeAvatax::Shared.tax_svc).to receive(:gettax).with(params)
94
+ SpreeAvatax::Shared.get_tax(params)
95
+ end
96
+
97
+ context 'with a timeout' do
98
+ let!(:config) { create(:avatax_config, timeout: 0.001) }
99
+ it 'times out' do
100
+ expect(SpreeAvatax::Shared.tax_svc).to(receive(:gettax) { sleep 0.1 })
101
+ expect {
102
+ SpreeAvatax::Shared.get_tax({})
103
+ }.to raise_error(SpreeAvatax::AvataxTimeout)
104
+ end
105
+ end
106
+ end
107
+
108
+ describe '.post_tax' do
109
+ it 'calls posttax' do
110
+ params = {}
111
+ expect(SpreeAvatax::Shared.tax_svc).to receive(:posttax).with(params)
112
+ SpreeAvatax::Shared.post_tax(params)
113
+ end
114
+
115
+ context 'with a timeout' do
116
+ let!(:config) { create(:avatax_config, timeout: 0.001) }
117
+ it 'times out' do
118
+ expect(SpreeAvatax::Shared.tax_svc).to(receive(:posttax) { sleep 0.1 })
119
+ expect {
120
+ SpreeAvatax::Shared.post_tax({})
121
+ }.to raise_error(SpreeAvatax::AvataxTimeout)
122
+ end
123
+ end
124
+ end
125
+
126
+ describe '.cancel_tax' do
127
+ it 'calls canceltax' do
128
+ params = {}
129
+ expect(SpreeAvatax::Shared.tax_svc).to receive(:canceltax).with(params)
130
+ SpreeAvatax::Shared.cancel_tax(params)
131
+ end
132
+
133
+ context 'with a timeout' do
134
+ let!(:config) { create(:avatax_config, timeout: 0.001) }
135
+ it 'times out' do
136
+ expect(SpreeAvatax::Shared.tax_svc).to(receive(:canceltax) { sleep 0.1 })
137
+ expect {
138
+ SpreeAvatax::Shared.cancel_tax({})
139
+ }.to raise_error(SpreeAvatax::AvataxTimeout)
140
+ end
141
+ end
142
+ end
89
143
  end
@@ -131,6 +131,17 @@ describe SpreeAvatax::ShortShipReturnInvoice do
131
131
 
132
132
  SpreeAvatax::ShortShipReturnInvoice.generate(unit_cancels: unit_cancels)
133
133
  end
134
+
135
+ context 'when avatax is disabled' do
136
+ let!(:config) { create(:avatax_config, enabled: false) }
137
+
138
+ it 'does nothing' do
139
+ expect(SpreeAvatax::Shared).to_not receive(:tax_svc)
140
+ expect {
141
+ subject
142
+ }.to_not change { SpreeAvatax::ShortShipReturnInvoice.count }
143
+ end
144
+ end
134
145
  end
135
146
 
136
147
  context 'with a successful response' do
@@ -1,15 +1,3 @@
1
- # Run Coverage report
2
- require "simplecov"
3
- SimpleCov.start do
4
- add_filter "spec/dummy"
5
- add_group "Controllers", "app/controllers"
6
- add_group "Helpers", "app/helpers"
7
- add_group "Mailers", "app/mailers"
8
- add_group "Models", "app/models"
9
- add_group "Views", "app/views"
10
- add_group "Libraries", "lib"
11
- end
12
-
13
1
  # Configure Rails Environment
14
2
  ENV["RAILS_ENV"] = "test"
15
3
 
metadata CHANGED
@@ -1,29 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solidus_avatax
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Solidus Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-27 00:00:00.000000000 Z
11
+ date: 2016-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: solidus_core
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: 1.1.0.pre
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '1.3'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
- - - "~>"
27
+ - - ">="
25
28
  - !ruby/object:Gem::Version
26
29
  version: 1.1.0.pre
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '1.3'
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: hashie
29
35
  requirement: !ruby/object:Gem::Requirement
@@ -80,20 +86,6 @@ dependencies:
80
86
  - - "~>"
81
87
  - !ruby/object:Gem::Version
82
88
  version: '3.2'
83
- - !ruby/object:Gem::Dependency
84
- name: simplecov
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
89
  - !ruby/object:Gem::Dependency
98
90
  name: sqlite3
99
91
  requirement: !ruby/object:Gem::Requirement
@@ -200,6 +192,7 @@ extra_rdoc_files: []
200
192
  files:
201
193
  - ".gitignore"
202
194
  - ".rspec"
195
+ - ".travis.yml"
203
196
  - Gemfile
204
197
  - LICENSE
205
198
  - README.md
@@ -213,6 +206,7 @@ files:
213
206
  - app/models/spree/reimbursement_decorator.rb
214
207
  - app/models/spree/tax_rate_decorator.rb
215
208
  - app/models/spree_avatax/calculator.rb
209
+ - app/models/spree_avatax/config.rb
216
210
  - app/models/spree_avatax/return_invoice.rb
217
211
  - app/models/spree_avatax/sales_invoice.rb
218
212
  - app/models/spree_avatax/sales_shared.rb
@@ -234,10 +228,10 @@ files:
234
228
  - db/migrate/20140911215422_add_canceled_at_and_cancel_transaction_id_to_sales_invoices.rb
235
229
  - db/migrate/20150427154942_create_spree_avatax_short_ship_return_invoices.rb
236
230
  - db/migrate/20150518172627_fix_avatax_short_ship_index.rb
231
+ - db/migrate/20151130195450_add_spree_avatax_configs.rb
237
232
  - lib/generators/solidus_avatax/install/install_generator.rb
238
233
  - lib/generators/solidus_avatax/install/templates/config/initializers/avatax.rb
239
234
  - lib/solidus_avatax.rb
240
- - lib/spree_avatax/config.rb
241
235
  - lib/spree_avatax/engine.rb
242
236
  - lib/spree_avatax/factories.rb
243
237
  - lib/tasks/commit_backfill.rake
@@ -285,29 +279,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
285
279
  requirements:
286
280
  - none
287
281
  rubyforge_project:
288
- rubygems_version: 2.2.5
282
+ rubygems_version: 2.5.1
289
283
  signing_key:
290
284
  specification_version: 4
291
285
  summary: Avatax extension for Solidus
292
- test_files:
293
- - spec/features/store_credits_spec.rb
294
- - spec/features/tax_calculation_spec.rb
295
- - spec/fixtures/vcr_cassettes/sales_invoice_gettax_with_discounts.yml
296
- - spec/fixtures/vcr_cassettes/sales_invoice_gettax_without_discounts.yml
297
- - spec/fixtures/vcr_cassettes/taxes_with_store_credits.yml
298
- - spec/models/spree/adjustment_spec.rb
299
- - spec/models/spree/order_contents_spec.rb
300
- - spec/models/spree/order_spec.rb
301
- - spec/models/spree/shipping_rate_spec.rb
302
- - spec/models/spree/tax_rate_spec.rb
303
- - spec/models/spree_avatax/calculator.rb
304
- - spec/models/spree_avatax/return_invoice_spec.rb
305
- - spec/models/spree_avatax/sales_invoice_spec.rb
306
- - spec/models/spree_avatax/sales_shared_spec.rb
307
- - spec/models/spree_avatax/shared_spec.rb
308
- - spec/models/spree_avatax/short_ship_return_invoice_spec.rb
309
- - spec/spec_helper.rb
310
- - spec/support/return_invoice_soap_responses.rb
311
- - spec/support/sales_invoice_soap_responses.rb
312
- - spec/support/short_ship_return_invoice_soap_responses.rb
313
- - spec/support/zone_support.rb
286
+ test_files: []
@@ -1,16 +0,0 @@
1
- module SpreeAvatax
2
- class Config
3
- class << self
4
- attr_accessor :username
5
- attr_accessor :password
6
- attr_accessor :company_code
7
- attr_accessor :service_url
8
- # These error handlers should be objects that respond to "call" and accept an order and an
9
- # exception as arguments. This allows you to ignore certain errors or handle them in
10
- # specific ways.
11
- attr_accessor :sales_invoice_generate_error_handler
12
- attr_accessor :sales_invoice_commit_error_handler
13
- attr_accessor :sales_invoice_cancel_error_handler
14
- end
15
- end
16
- end