solidus_avatax_certified 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.env_example +4 -0
- data/.gitignore +16 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/GEM_VERSION +1 -0
- data/Gemfile +18 -0
- data/LICENSE +26 -0
- data/README.md +27 -0
- data/Rakefile +21 -0
- data/app/assets/javascripts/spree/backend/address_validator.js +84 -0
- data/app/assets/javascripts/spree/backend/solidus_avatax_certified.js +5 -0
- data/app/assets/javascripts/spree/backend/use_code_picker.js +51 -0
- data/app/assets/javascripts/spree/frontend/address_validator.js +87 -0
- data/app/assets/javascripts/spree/frontend/flash.js.coffee +26 -0
- data/app/assets/javascripts/spree/frontend/solidus_avatax_certified.js +4 -0
- data/app/assets/stylesheets/spree/backend/solidus_avatax_certified.css +4 -0
- data/app/assets/stylesheets/spree/frontend/solidus_avatax_certified.css +4 -0
- data/app/controllers/spree/admin/avalara_entity_use_codes_controller.rb +15 -0
- data/app/controllers/spree/admin/avatax_settings_controller.rb +82 -0
- data/app/controllers/spree/admin/users_controller_decorator.rb +11 -0
- data/app/controllers/spree/checkout_controller_decorator.rb +22 -0
- data/app/models/solidus_avatax_certified/address.rb +95 -0
- data/app/models/solidus_avatax_certified/avatax_log.rb +69 -0
- data/app/models/solidus_avatax_certified/line.rb +146 -0
- data/app/models/solidus_avatax_certified/preference_updater.rb +74 -0
- data/app/models/spree/address_decorator.rb +13 -0
- data/app/models/spree/adjustment_decorator.rb +10 -0
- data/app/models/spree/avalara_entity_use_code.rb +5 -0
- data/app/models/spree/avalara_preference.rb +72 -0
- data/app/models/spree/avalara_transaction.rb +181 -0
- data/app/models/spree/calculator/avalara_transaction.rb +86 -0
- data/app/models/spree/line_item_decorator.rb +25 -0
- data/app/models/spree/order_decorator.rb +85 -0
- data/app/models/spree/payment_decorator.rb +23 -0
- data/app/models/spree/refund_decorator.rb +30 -0
- data/app/models/spree/shipment_decorator.rb +28 -0
- data/app/models/spree/shipping_rate_decorator.rb +25 -0
- data/app/models/spree/user_decorator.rb +3 -0
- data/app/models/tax_svc.rb +143 -0
- data/app/overrides/spree/admin/shared/_configuration_menu.rb +10 -0
- data/app/overrides/spree/admin/users/sidebar.rb +8 -0
- data/app/overrides/spree/admin/users/validation_button.rb +6 -0
- data/app/views/spree/admin/avalara_entity_use_codes/_form.html.erb +27 -0
- data/app/views/spree/admin/avalara_entity_use_codes/edit.html.erb +16 -0
- data/app/views/spree/admin/avalara_entity_use_codes/index.html.erb +33 -0
- data/app/views/spree/admin/avalara_entity_use_codes/new.html.erb +17 -0
- data/app/views/spree/admin/avalara_entity_use_codes/show.html.erb +24 -0
- data/app/views/spree/admin/avatax_settings/edit.html.erb +183 -0
- data/app/views/spree/admin/avatax_settings/ping_my_service.js.erb +8 -0
- data/app/views/spree/admin/avatax_settings/show.html.erb +124 -0
- data/app/views/spree/admin/avatax_settings/validate_address.js.erb +8 -0
- data/app/views/spree/admin/users/avalara_information.html.erb +53 -0
- data/app/views/spree/checkout/_address.html.erb +35 -0
- data/app/views/spree/checkout/_address_validator_button.html.erb +3 -0
- data/bin/rails +7 -0
- data/circle.yml +17 -0
- data/config/initializers/avatax.rb +5 -0
- data/config/initializers/spree.rb +3 -0
- data/config/locales/en.yml +35 -0
- data/config/routes.rb +18 -0
- data/db/migrate/20160624154205_create_spree_avalara_transactions.rb +9 -0
- data/db/migrate/20160624154423_create_spree_avalara_entity_use_codes.rb +9 -0
- data/db/migrate/20160624155217_add_columns_to_spree_users.rb +6 -0
- data/db/migrate/20160628200504_create_spree_avalara_preferences.rb +10 -0
- data/db/migrate/20160805193512_add_vat_id_to_spree_users.rb +5 -0
- data/db/seeds.rb +1 -0
- data/lib/generators/solidus_avatax_certified/install/install_generator.rb +45 -0
- data/lib/solidus_avatax_certified/engine.rb +22 -0
- data/lib/solidus_avatax_certified/preference_seeder.rb +69 -0
- data/lib/solidus_avatax_certified/seeder.rb +117 -0
- data/lib/solidus_avatax_certified.rb +2 -0
- data/lib/tasks/load_seeds.rake +15 -0
- data/setup.md +12 -0
- data/solidus_avatax_certified.gemspec +42 -0
- data/spec/controllers/spree/admin/avalara_entity_use_codes_controller_spec.rb +53 -0
- data/spec/controllers/spree/admin/avatax_settings_controller_spec.rb +67 -0
- data/spec/factories/avalara_entity_use_code_factory.rb +6 -0
- data/spec/factories/avalara_factories.rb +76 -0
- data/spec/factories/avalara_order_factory.rb +62 -0
- data/spec/factories/avalara_preference_factory.rb +7 -0
- data/spec/factories/avalara_shipment_factory.rb +27 -0
- data/spec/factories/avalara_shipping_method_factory.rb +23 -0
- data/spec/factories/tax_rate_factory.rb +19 -0
- data/spec/features/certification_spec.rb +77 -0
- data/spec/features/checkout_spec.rb +156 -0
- data/spec/features/vat_spec.rb +153 -0
- data/spec/models/solidus_avatax_certified/address_spec.rb +80 -0
- data/spec/models/solidus_avatax_certified/avatax_log_spec.rb +97 -0
- data/spec/models/solidus_avatax_certified/line_spec.rb +100 -0
- data/spec/models/spree/address_decorator_spec.rb +44 -0
- data/spec/models/spree/adjustment_decorator_spec.rb +25 -0
- data/spec/models/spree/avalara_entity_use_code_spec.rb +5 -0
- data/spec/models/spree/avalara_preference_spec.rb +173 -0
- data/spec/models/spree/avalara_transaction_spec.rb +203 -0
- data/spec/models/spree/calculator/avalara_transaction_spec.rb +129 -0
- data/spec/models/spree/line_item_decorator_spec.rb +33 -0
- data/spec/models/spree/order_decorator_spec.rb +164 -0
- data/spec/models/spree/payment_decorator_spec.rb +117 -0
- data/spec/models/spree/refund_decorator_spec.rb +81 -0
- data/spec/models/spree/shipment_decorator_spec.rb +36 -0
- data/spec/models/spree/shipping_rate_decorator_spec.rb +17 -0
- data/spec/models/spree/user_decorator_spec.rb +5 -0
- data/spec/spec_helper.rb +81 -0
- data/spec/support/avatax_config_preferences.rb +8 -0
- data/spec/support/vcr.rb +9 -0
- data/spec/vcr/Certification/Exempt_sales_should_be_reflected_in_the_test_data_through_use_of_ExemptionNo_or_CustomerUsageType_/does_not_add_additional_tax.yml +276 -0
- data/spec/vcr/Certification/Transactions_have_been_committed_/commits_an_order.yml +336 -0
- data/spec/vcr/Certification/Transactions_have_been_voided/cancelled_/should_be_successful/returns_ResultCode_with_value_Success.yml +522 -0
- data/spec/vcr/Certification/return_orders/_commit_avatax_final/should_commit_avatax_final.yml +404 -0
- data/spec/vcr/Checkout/complete_order/has_tax_and_shipping_tax_adjustments_on_page.yml +72 -0
- data/spec/vcr/Checkout/complete_order/order_line_items_and_shipments_have_an_additional_tax_total_sum_of_0_40.yml +72 -0
- data/spec/vcr/Checkout/payment/tax_included/has_tax_and_shipping_tax_adjustments_on_page.yml +72 -0
- data/spec/vcr/Checkout/payment/tax_included/order_line_items_and_shipments_have_an_included_tax_total_sum_of_0_38.yml +72 -0
- data/spec/vcr/Checkout/payment/tax_not_included/on_payment_page/has_tax_and_shipping_tax_adjustments_on_page.yml +72 -0
- data/spec/vcr/Checkout/payment/tax_not_included/on_payment_page/order_line_items_and_shipments_and_shipments_have_an_additional_tax_total_sum_of_0_40.yml +72 -0
- data/spec/vcr/Checkout/payment/with_promotion/tax_not_included/has_adjusted_tax_amount_after_promotion_applied.yml +73 -0
- data/spec/vcr/SolidusAvataxCertified_Address/_validate/fails_when_information_is_incorrect.yml +54 -0
- data/spec/vcr/Spree_Calculator_AvalaraTransaction/_compute/when_computing_a_line_item/when_tax_is_included_in_price/should_be_equal_to_the_item_pre-tax_total_rate.yml +137 -0
- data/spec/vcr/Spree_Calculator_AvalaraTransaction/_compute/when_computing_a_line_item/when_tax_is_included_in_price/should_be_equal_to_the_previous_included_tax_total_is_order_is_at_address.yml +138 -0
- data/spec/vcr/Spree_Calculator_AvalaraTransaction/_compute/when_computing_a_line_item/when_tax_is_included_in_price/should_be_equal_to_the_previous_included_tax_total_is_order_is_at_cart.yml +137 -0
- data/spec/vcr/Spree_Calculator_AvalaraTransaction/_compute/when_computing_a_line_item/when_tax_is_not_included_in_price/should_be_equal_to_the_item_pre-tax_total_rate.yml +136 -0
- data/spec/vcr/Spree_Calculator_AvalaraTransaction/_compute/when_computing_a_line_item/when_tax_is_not_included_in_price/should_be_equal_to_the_previous_additional_tax_total_if_order_is_at_address.yml +137 -0
- data/spec/vcr/Spree_Calculator_AvalaraTransaction/_compute/when_computing_a_line_item/when_tax_is_not_included_in_price/should_be_equal_to_the_previous_additional_tax_total_if_order_is_at_cart.yml +136 -0
- data/spec/vcr/Spree_Calculator_AvalaraTransaction/_compute/when_computing_a_line_item/when_tax_is_not_included_in_price/should_be_equal_to_the_previous_tax_total_if_preference_tax_calculation_is_false.yml +136 -0
- data/spec/vcr/Spree_Calculator_AvalaraTransaction/_compute/when_computing_a_line_item/when_tax_is_not_included_in_price/when_the_line_item_is_discounted/should_be_equal_to_the_items_pre-tax_total_rate.yml +276 -0
- data/spec/vcr/Spree_Calculator_AvalaraTransaction/_compute/when_computing_a_line_item/when_tax_is_not_included_in_price/when_the_order_is_discounted/should_be_equal_to_the_items_pre-tax_total_rate.yml +206 -0
- data/spec/vcr/Spree_Calculator_AvalaraTransaction/_compute/when_given_a_shipment/computing_normal_shipment/should_be_equal_4_0.yml +141 -0
- data/spec/vcr/Spree_Calculator_AvalaraTransaction/_compute/when_given_a_shipment/when_tax_is_included_in_price/should_be_equal_to_3_85.yml +143 -0
- data/spec/vcr/Spree_Calculator_AvalaraTransaction/_compute/when_given_a_shipment/with_promotion/should_equal_3_96.yml +210 -0
- data/spec/vcr/Spree_Calculator_AvalaraTransaction/_compute/when_given_an_order/when_computing_an_order/should_raise_error.yml +136 -0
- data/spec/vcr/Spree_Order/_cancel_avalara/should_receive_cancel_order_when_cancel_avalara_is_called.yml +136 -0
- data/spec/vcr/Spree_Order/_cancel_avalara/state_machine_event_cancel/should_recieve_cancel_avalara_when_event_cancel_is_called.yml +259 -0
- data/spec/vcr/Spree_Order/_validate_ship_address/should_return_false_if_validation_failed.yml +54 -0
- data/spec/vcr/Spree_Order/_validate_ship_address/should_return_the_response_if_refuse_checkout_on_address_validation_is_disabled.yml +59 -0
- data/spec/vcr/Spree_Order/_validate_ship_address/should_return_the_response_if_validation_is_success.yml +59 -0
- data/spec/vcr/Spree_Payment/_avalara_finalize/should_update_the_amount_to_be_the_order_total.yml +136 -0
- data/spec/vcr/Spree_Payment/_cancel_avalara/committed_order/should_be_successful/ResultCode_returns_Success.yml +205 -0
- data/spec/vcr/Spree_Payment/_cancel_avalara/uncommitted_order/should_fail/ResultCode_returns_Error.yml +191 -0
- data/spec/vcr/Spree_Payment/_purchase_/receive_avalara_finalize.yml +136 -0
- data/spec/vcr/Spree_Payment/_void_transaction_/receive_cancel_avalara.yml +136 -0
- data/spec/vcr/Spree_Refund/full_refund/returns_correct_tax_calculations.yml +270 -0
- data/spec/vcr/VAT/Seller_in_EU_country_Buyer_in_another_EU_country/Seller_does_not_have_Nexus_Jurisdition_Registered/TotalTax_is_equal_to_order_included_tax_total.yml +137 -0
- data/spec/vcr/VAT/Seller_in_EU_country_Buyer_in_another_EU_country/Seller_does_not_have_Nexus_Jurisdition_Registered/origin_country_tax_is_returned.yml +138 -0
- data/spec/vcr/VAT/Seller_in_EU_country_Buyer_in_another_EU_country/Seller_does_not_have_Nexus_Jurisdition_Registered/with_BusinessIdentificationNo/origin_country_zero_rate_is_returned.yml +143 -0
- data/spec/vcr/VAT/Seller_in_EU_country_Buyer_in_another_EU_country/Seller_has_Nexus_Jurisdition_Registered/TotalTax_is_equal_to_order_included_tax_total.yml +139 -0
- data/spec/vcr/VAT/Seller_in_EU_country_Buyer_in_another_EU_country/Seller_has_Nexus_Jurisdition_Registered/destination_country_tax_is_returned.yml +139 -0
- data/spec/vcr/VAT/Seller_in_EU_country_Buyer_in_another_EU_country/Seller_has_Nexus_Jurisdition_Registered/with_BusinessIdentificationNo/origin_country_zero_rate_is_returned.yml +144 -0
- data/spec/vcr/VAT/Seller_in_EU_country_Buyer_in_same_EU_country/TotalTax_is_equal_to_order_included_tax_total.yml +137 -0
- data/spec/vcr/VAT/Seller_in_EU_country_Buyer_in_same_EU_country/tax_detail_country_equals_to_IT.yml +138 -0
- data/spec/vcr/VAT/Seller_in_EU_country_Buyer_is_outside_EU/Seller_does_not_have_Nexus_Jurisdition_registered/TotalTax_is_equal_to_order_included_tax_total.yml +137 -0
- data/spec/vcr/VAT/Seller_in_EU_country_Buyer_is_outside_EU/Seller_does_not_have_Nexus_Jurisdition_registered/tax_detail_country_equals_to_IT.yml +137 -0
- data/spec/vcr/VAT/Seller_in_EU_country_Buyer_is_outside_EU/Seller_does_not_have_Nexus_Jurisdition_registered/total_tax_is_0_since_utah_is_not_in_jurisdiction.yml +137 -0
- data/spec/vcr/VAT/Seller_in_EU_country_Buyer_is_outside_EU/Seller_does_not_have_Nexus_Jurisdition_registered/with_BusinessIdentificationNo/origin_country_zero_rate_is_returned.yml +138 -0
- data/spec/vcr/VAT/Seller_in_EU_country_Buyer_is_outside_EU/Seller_has_Nexus_Jurisdiction_Registered/TotalTax_is_equal_to_order_included_tax_total.yml +195 -0
- data/spec/vcr/VAT/Seller_in_EU_country_Buyer_is_outside_EU/Seller_has_Nexus_Jurisdiction_Registered/tax_detail_region_equals_to_AL.yml +195 -0
- data/spec/vcr/address_validation_success.yml +59 -0
- data/spec/vcr/capture_with_customer_usage_type.yml +72 -0
- data/spec/vcr/order_cancel.yml +258 -0
- data/spec/vcr/order_capture.yml +72 -0
- data/spec/vcr/order_capture_finalize.yml +141 -0
- data/spec/vcr/order_capture_with_promo.yml +73 -0
- data/spec/vcr/order_return_capture.yml +68 -0
- data/spec/vcr/tax_included_order.yml +73 -0
- metadata +581 -0
@@ -0,0 +1,69 @@
|
|
1
|
+
module SolidusAvataxCertified
|
2
|
+
class PreferenceSeeder
|
3
|
+
BOOLEAN_PREFERENCES = ['log', 'address_validation', 'tax_calculation', 'document_commit', 'log_to_stdout', 'refuse_checkout_address_validation_error', 'customer_can_validate'].freeze
|
4
|
+
STORABLE_ENV_PREFERENCES = ['company_code', 'endpoint', 'account', 'license_key'].freeze
|
5
|
+
|
6
|
+
class << self
|
7
|
+
|
8
|
+
def seed!(print_messages=true)
|
9
|
+
@print_messages = print_messages
|
10
|
+
stored_env_prefs
|
11
|
+
boolean_prefs
|
12
|
+
enabled_countries_pref
|
13
|
+
origin_address
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def stored_env_prefs
|
19
|
+
STORABLE_ENV_PREFERENCES.each do |env|
|
20
|
+
if !ENV["AVATAX_#{env.upcase}"].blank?
|
21
|
+
value = ENV["AVATAX_#{env.upcase}"]
|
22
|
+
else
|
23
|
+
value = nil
|
24
|
+
end
|
25
|
+
|
26
|
+
pref = Spree::AvalaraPreference.new(name: env, value: value, object_type: 'string')
|
27
|
+
|
28
|
+
save_preference(pref)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def boolean_prefs
|
33
|
+
BOOLEAN_PREFERENCES.each do |preference|
|
34
|
+
if ['refuse_checkout_address_validation_error', 'log_to_stdout'].include?(preference)
|
35
|
+
pref = Spree::AvalaraPreference.new(name: preference, value: 'false', object_type: 'boolean')
|
36
|
+
else
|
37
|
+
pref = Spree::AvalaraPreference.new(name: preference, value: 'true', object_type: 'boolean')
|
38
|
+
end
|
39
|
+
|
40
|
+
save_preference(pref)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def enabled_countries_pref
|
45
|
+
pref = Spree::AvalaraPreference.new(name: 'address_validation_enabled_countries', value: 'United States,Canada', object_type: 'array')
|
46
|
+
save_preference(pref)
|
47
|
+
end
|
48
|
+
|
49
|
+
def origin_address
|
50
|
+
pref = Spree::AvalaraPreference.find_or_create_by(name: 'origin_address', object_type: 'json')
|
51
|
+
pref.value = "{}" if pref.value.nil?
|
52
|
+
|
53
|
+
save_preference(pref)
|
54
|
+
end
|
55
|
+
|
56
|
+
def save_preference(preference)
|
57
|
+
if preference.save
|
58
|
+
success_message(preference) if @print_messages
|
59
|
+
else
|
60
|
+
puts "#{preference.errors.full_messages.to_sentence}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def success_message(preference)
|
65
|
+
puts "Created: #{preference.name} - #{preference.value ? preference.value : 'Please input value in avalara settings!'}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module SolidusAvataxCertified
|
2
|
+
class Seeder
|
3
|
+
class << self
|
4
|
+
|
5
|
+
def seed!
|
6
|
+
create_use_codes
|
7
|
+
create_tax
|
8
|
+
add_tax_category_to_shipping_methods
|
9
|
+
add_tax_category_to_products
|
10
|
+
populate_default_stock_location
|
11
|
+
|
12
|
+
puts "***** SOLIDUS AVATAX CERTIFIED *****"
|
13
|
+
puts ""
|
14
|
+
puts "Please remember to:"
|
15
|
+
puts "- Add tax category to all shipping methods that need to be taxed."
|
16
|
+
puts "- Don't assign anything default tax."
|
17
|
+
puts "- Assign proper Tax Category to each product"
|
18
|
+
puts "- Fill in Stock Location Address."
|
19
|
+
puts "- Fill Origin Address in Avatax Settings."
|
20
|
+
puts ""
|
21
|
+
puts "***** SOLIDUS AVATAX CERTIFIED *****"
|
22
|
+
end
|
23
|
+
|
24
|
+
def seed_use_codes!
|
25
|
+
create_use_codes
|
26
|
+
puts "***** SOLIDUS AVATAX CERTIFIED: Use Codes Seeded"
|
27
|
+
end
|
28
|
+
|
29
|
+
def create_tax
|
30
|
+
default_tax_category = Spree::TaxCategory.find_by(name: 'Default')
|
31
|
+
default_tax_rate = Spree::TaxRate.find_by(name: 'North America')
|
32
|
+
|
33
|
+
default_tax_category.destroy if default_tax_category
|
34
|
+
default_tax_rate.destroy if default_tax_rate
|
35
|
+
|
36
|
+
clothing = Spree::TaxCategory.find_or_create_by(name: 'Clothing')
|
37
|
+
clothing.update_attributes(tax_code: 'P0000000')
|
38
|
+
tax_zone = Spree::Zone.find_or_create_by(name: 'North America')
|
39
|
+
tax_calculator = Spree::Calculator::AvalaraTransaction.create!
|
40
|
+
sales_tax = Spree::TaxRate.find_or_create_by(name: 'Tax') do |tax_rate|
|
41
|
+
# default values for the create
|
42
|
+
tax_rate.amount = BigDecimal.new('0')
|
43
|
+
tax_rate.calculator = tax_calculator
|
44
|
+
tax_rate.tax_category = clothing
|
45
|
+
end
|
46
|
+
sales_tax.update!(tax_category: clothing, name: 'Tax', amount: BigDecimal.new('0'), zone: tax_zone, show_rate_in_label: false, calculator: tax_calculator)
|
47
|
+
|
48
|
+
shipping = Spree::TaxCategory.find_or_create_by(name: 'Shipping', tax_code: 'FR000000')
|
49
|
+
shipping_tax = Spree::TaxRate.find_or_create_by(name: 'Shipping Tax') do |shipping_tax|
|
50
|
+
shipping_tax.tax_category = shipping
|
51
|
+
shipping_tax.amount = BigDecimal.new('0')
|
52
|
+
shipping_tax.zone = tax_zone
|
53
|
+
shipping_tax.show_rate_in_label = false
|
54
|
+
end
|
55
|
+
shipping_tax.update!(tax_category: shipping, amount: BigDecimal.new('0'), zone: Spree::Zone.find_by_name('North America'), show_rate_in_label: false, calculator: Spree::Calculator::AvalaraTransaction.create!)
|
56
|
+
end
|
57
|
+
|
58
|
+
def add_tax_category_to_shipping_methods
|
59
|
+
Spree::ShippingMethod.update_all(tax_category_id: Spree::TaxCategory.find_by(name: 'Shipping').id)
|
60
|
+
end
|
61
|
+
|
62
|
+
def add_tax_category_to_products
|
63
|
+
Spree::Product.update_all(tax_category_id: Spree::TaxCategory.find_by(name: 'Clothing').id)
|
64
|
+
end
|
65
|
+
|
66
|
+
def populate_default_stock_location
|
67
|
+
default = Spree::StockLocation.find_or_create_by(name: 'default')
|
68
|
+
|
69
|
+
return unless default.zipcode.nil? || default.address1.nil?
|
70
|
+
|
71
|
+
state = Spree::State.find_by(name: 'Alabama')
|
72
|
+
|
73
|
+
address = {
|
74
|
+
address1: '915 S Jackson St',
|
75
|
+
city: 'Montgomery',
|
76
|
+
state: state,
|
77
|
+
country: state.country,
|
78
|
+
zipcode: '36104',
|
79
|
+
default: true,
|
80
|
+
name: 'default',
|
81
|
+
backorderable_default: true
|
82
|
+
}
|
83
|
+
|
84
|
+
default.update_attributes(address)
|
85
|
+
end
|
86
|
+
|
87
|
+
def create_use_codes
|
88
|
+
unless Spree::AvalaraEntityUseCode.count >= 16
|
89
|
+
use_codes.each do |key, value|
|
90
|
+
Spree::AvalaraEntityUseCode.find_or_create_by(use_code: key, use_code_description: value)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def use_codes
|
96
|
+
{
|
97
|
+
"A" => "Federal government",
|
98
|
+
"B" => "State government",
|
99
|
+
"C" => "Tribe/Status Indian/Indian Band",
|
100
|
+
"D" => "Foreign diplomat",
|
101
|
+
"E" => "Charitable or benevolent organization",
|
102
|
+
"F" => "Religious or educational organization",
|
103
|
+
"G" => "Resale",
|
104
|
+
"H" => "Commercial agricultural production",
|
105
|
+
"I" => "Industrial production/manufacturer",
|
106
|
+
"J" => "Direct pay permit",
|
107
|
+
"K" => "Direct mail",
|
108
|
+
"L" => "Other",
|
109
|
+
"N" => "Local government",
|
110
|
+
"P" => "Commercial aquaculture (Canada only)",
|
111
|
+
"Q" => "Commercial fishery (Canada only)",
|
112
|
+
"R" => "Non-resident (Canada only)"
|
113
|
+
}
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
namespace :solidus_avatax_certified do
|
2
|
+
desc "Loads seed data."
|
3
|
+
task load_seeds: :environment do
|
4
|
+
SolidusAvataxCertified::Seeder.seed!
|
5
|
+
SolidusAvataxCertified::PreferenceSeeder.seed!
|
6
|
+
end
|
7
|
+
|
8
|
+
task load_preferences: :environment do
|
9
|
+
SolidusAvataxCertified::PreferenceSeeder.seed!
|
10
|
+
end
|
11
|
+
|
12
|
+
task load_use_codes: :environment do
|
13
|
+
SolidusAvataxCertified::Seeder.seed_use_codes!
|
14
|
+
end
|
15
|
+
end
|
data/setup.md
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
Setup Steps
|
2
|
+
===========
|
3
|
+
|
4
|
+
* Setup Avalara gem
|
5
|
+
* Create config/initializer/avalara.rb
|
6
|
+
* Set up avalara username, password, endpoint, and avatax origin
|
7
|
+
|
8
|
+
Avatax Gem Setup
|
9
|
+
================
|
10
|
+
* bundle exec rails g solidus_avatax_certified:install
|
11
|
+
* Stock location needs to be set up in order for gem to work
|
12
|
+
* Fill in Avalara Settings information
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
gem_version = File.read(File.expand_path('../GEM_VERSION',__FILE__)).strip
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.platform = Gem::Platform::RUBY
|
6
|
+
s.name = 'solidus_avatax_certified'
|
7
|
+
s.version = gem_version
|
8
|
+
s.summary = 'Solidus extension for Avalara tax calculation.'
|
9
|
+
s.description = 'Solidus extension for Avalara tax calculation.'
|
10
|
+
s.required_ruby_version = '>= 2.1'
|
11
|
+
|
12
|
+
s.author = 'Allison Reilly'
|
13
|
+
s.email = 'acreilly3@gmail.com'
|
14
|
+
s.homepage = 'http://www.boomer.digital'
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.require_path = "lib"
|
19
|
+
s.requirements << "none"
|
20
|
+
|
21
|
+
s.add_dependency "solidus_core", [">= 1.0.0", "< 2.1.0"]
|
22
|
+
s.add_dependency "json", "~> 1.8"
|
23
|
+
s.add_dependency "addressable", "~> 2.4"
|
24
|
+
s.add_dependency "rest-client", "~> 1.7"
|
25
|
+
s.add_dependency "logging", "~> 2.0"
|
26
|
+
|
27
|
+
s.add_development_dependency "dotenv"
|
28
|
+
s.add_development_dependency "rspec-rails", "~> 3.2"
|
29
|
+
s.add_development_dependency "simplecov"
|
30
|
+
s.add_development_dependency "sqlite3"
|
31
|
+
s.add_development_dependency "sass-rails"
|
32
|
+
s.add_development_dependency "coffee-rails"
|
33
|
+
s.add_development_dependency "factory_girl"
|
34
|
+
s.add_development_dependency "selenium-webdriver", "~> 2.53.4"
|
35
|
+
s.add_development_dependency "capybara"
|
36
|
+
s.add_development_dependency "capybara-screenshot"
|
37
|
+
s.add_development_dependency 'capybara-accessible'
|
38
|
+
s.add_development_dependency "database_cleaner"
|
39
|
+
s.add_development_dependency 'shoulda-matchers', '~> 2.7'
|
40
|
+
s.add_development_dependency 'vcr'
|
41
|
+
s.add_development_dependency 'webmock'
|
42
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Spree::Admin::AvalaraEntityUseCodesController do
|
4
|
+
let(:avalara_entity_use_code) { FactoryGirl.create(:avalara_entity_use_code) }
|
5
|
+
|
6
|
+
stub_authorization!
|
7
|
+
|
8
|
+
before :each do
|
9
|
+
DatabaseCleaner.clean
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#index' do
|
13
|
+
subject { get :index }
|
14
|
+
|
15
|
+
it { is_expected.to be_success }
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#show' do
|
19
|
+
subject { get :show, params: { id: avalara_entity_use_code.id } }
|
20
|
+
|
21
|
+
it { is_expected.to be_success }
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#new' do
|
25
|
+
subject { get :new }
|
26
|
+
|
27
|
+
it { is_expected.to be_success }
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#edit' do
|
31
|
+
subject { get :edit, params: { id: avalara_entity_use_code.id} }
|
32
|
+
|
33
|
+
it { is_expected.to be_success }
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#update' do
|
37
|
+
let(:params) do
|
38
|
+
{
|
39
|
+
id: avalara_entity_use_code.to_param,
|
40
|
+
avalara_entity_use_code: {
|
41
|
+
use_code: '55',
|
42
|
+
}
|
43
|
+
}
|
44
|
+
end
|
45
|
+
subject { put :update, params: params }
|
46
|
+
|
47
|
+
it { is_expected.to redirect_to(spree.admin_avalara_entity_use_codes_path) }
|
48
|
+
|
49
|
+
it 'should update use_code' do
|
50
|
+
expect{subject}.to change { avalara_entity_use_code.reload.use_code }.from('A').to('55')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Spree::Admin::AvataxSettingsController, :type => :controller do
|
4
|
+
|
5
|
+
stub_authorization!
|
6
|
+
|
7
|
+
describe '/avatax_settings' do
|
8
|
+
subject { get :show }
|
9
|
+
it { should be_success }
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '/avatax_settings/edit' do
|
13
|
+
subject { get :edit }
|
14
|
+
it { should be_success }
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '/avatax_settings/get_file_post_order_to_avalara' do
|
18
|
+
before { File.new("#{Rails.root}/log/post_order_to_avalara.log", 'w') }
|
19
|
+
after { File.delete("#{Rails.root}/log/post_order_to_avalara.log") }
|
20
|
+
|
21
|
+
subject { get :get_file_post_order_to_avalara }
|
22
|
+
it { should be_success }
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '/avatax_settings/erase_data' do
|
26
|
+
it 'erases the log' do
|
27
|
+
Dir.mkdir('log') unless Dir.exist?('log')
|
28
|
+
file = File.open("log/test.log", 'w') { |f| f.write('Hyah!') }
|
29
|
+
|
30
|
+
expect(File.read('log/test.log')).to eq('Hyah!')
|
31
|
+
|
32
|
+
get :erase_data, params: { log_name: 'test' }
|
33
|
+
|
34
|
+
expect(File.read('log/test.log')).to eq('')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '/avatax_settings/ping_my_service' do
|
39
|
+
it 'flashes message' do
|
40
|
+
subject { get :ping_my_service }
|
41
|
+
response.should be_success
|
42
|
+
flash.should_not be_nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#update' do
|
47
|
+
let(:params) do
|
48
|
+
{
|
49
|
+
address: {
|
50
|
+
Line1: "",
|
51
|
+
Line2: "",
|
52
|
+
City: "",
|
53
|
+
Region: "",
|
54
|
+
PostalCode: "",
|
55
|
+
Country: ""
|
56
|
+
},
|
57
|
+
settings: {
|
58
|
+
account: '123456789',
|
59
|
+
address_validation_enabled_countries: []
|
60
|
+
}
|
61
|
+
}
|
62
|
+
end
|
63
|
+
subject { put :update, params: params }
|
64
|
+
|
65
|
+
it { is_expected.to redirect_to(spree.admin_avatax_settings_path) }
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
FactoryGirl.define do
|
2
|
+
factory :request_hash, class: Hash do
|
3
|
+
Commit false
|
4
|
+
CustomerCode '1'
|
5
|
+
DocDate '2014-11-03'
|
6
|
+
CompanyCode '54321'
|
7
|
+
CustomerUsageType ''
|
8
|
+
ExemptionNo nil
|
9
|
+
Client AVATAX_CLIENT_VERSION
|
10
|
+
DocCode 'R731071205'
|
11
|
+
ReferenceCode 'R731071205'
|
12
|
+
DetailLevel 'Tax'
|
13
|
+
DocType 'SalesOrder'
|
14
|
+
Discount '0.00'
|
15
|
+
Addresses [{:AddressCode=>'9', :Line1=>'31 South St', :City=>'Morristown', :PostalCode=>'07960', :Country=>'US'},{:AddressCode=>'Dest', :Line1=>'73 Glenmere Drive', :Line2=>'', :City=>'Chatham', :Region=>'NJ', :Country=>'US', :PostalCode=>'07928'},{:AddressCode=>'Orig', :Line1=>'73 Glenmere Drive', :City=>'Chatham', :PostalCode=>'07928', :Country=>'United States'}]
|
16
|
+
Lines [{:LineNo=>'1-LI', :ItemCode=>'ROR-00013', :Qty=>3, :Amount=>62.97, :OriginCode=>'9', :DestinationCode=>'Dest', :Description=>'Ruby on Rails Jr. Spaghetti', :TaxCode=>'P0000000', :Discounted=>false}]
|
17
|
+
end
|
18
|
+
|
19
|
+
factory :avalara_transaction_calculator, class: Spree::Calculator::AvalaraTransaction do
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
FactoryGirl.modify do
|
24
|
+
factory :tax_category, class: Spree::TaxCategory do
|
25
|
+
name { "TaxCategory - #{rand(999999)}" }
|
26
|
+
tax_code { 'PC030000' }
|
27
|
+
end
|
28
|
+
|
29
|
+
factory :address, class: Spree::Address do
|
30
|
+
transient do
|
31
|
+
country_iso_code 'US'
|
32
|
+
state_code 'AL'
|
33
|
+
end
|
34
|
+
|
35
|
+
firstname 'John'
|
36
|
+
lastname 'Doe'
|
37
|
+
company 'Company'
|
38
|
+
address1 '915 S Jackson St'
|
39
|
+
address2 ''
|
40
|
+
city 'Montgomery'
|
41
|
+
state_name 'Alabama'
|
42
|
+
zipcode '36104'
|
43
|
+
phone '555-555-0199'
|
44
|
+
alternative_phone '555-555-0199'
|
45
|
+
|
46
|
+
state do |address|
|
47
|
+
if !Spree::State.find_by(name: address.state_name).nil?
|
48
|
+
Spree::State.find_by(name: address.state_name)
|
49
|
+
else
|
50
|
+
address.association(:state)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
country do |address|
|
55
|
+
if address.state
|
56
|
+
address.state.country
|
57
|
+
else
|
58
|
+
address.association(:country, iso: country_iso_code)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
factory :ship_address, parent: :address do
|
65
|
+
address1 '915 S Jackson St'
|
66
|
+
end
|
67
|
+
|
68
|
+
# Adding this modifier since US country name changes between solidus versions
|
69
|
+
factory :country, class: Spree::Country do
|
70
|
+
iso_name 'UNITED STATES'
|
71
|
+
name 'United States'
|
72
|
+
iso 'US'
|
73
|
+
iso3 'USA'
|
74
|
+
numcode 840
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
FactoryGirl.define do
|
2
|
+
factory :avalara_order, class: Spree::Order do
|
3
|
+
user
|
4
|
+
bill_address
|
5
|
+
ship_address
|
6
|
+
completed_at nil
|
7
|
+
email { user.email }
|
8
|
+
store
|
9
|
+
state 'delivery'
|
10
|
+
|
11
|
+
transient do
|
12
|
+
line_items_price BigDecimal.new(10)
|
13
|
+
line_items_count 1
|
14
|
+
line_items_quantity 1
|
15
|
+
shipment_cost 5
|
16
|
+
tax_category Spree::TaxCategory.first
|
17
|
+
tax_included false
|
18
|
+
end
|
19
|
+
|
20
|
+
before(:create) do |order, evaluator|
|
21
|
+
if Spree::Country.count == 0
|
22
|
+
create(:country)
|
23
|
+
end
|
24
|
+
if Spree::Zone.find_by(name: 'GlobalZone').nil?
|
25
|
+
create(:global_zone, default_tax: true)
|
26
|
+
end
|
27
|
+
if Spree::TaxCategory.first.nil?
|
28
|
+
create(:clothing_tax_rate, tax_category: create(:tax_category), included_in_price: evaluator.tax_included)
|
29
|
+
else
|
30
|
+
create(:clothing_tax_rate, tax_category: Spree::TaxCategory.first, included_in_price: evaluator.tax_included)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
after(:create) do |order, evaluator|
|
35
|
+
create_list(:line_item, evaluator.line_items_count, order: order, price: evaluator.line_items_price, tax_category: evaluator.tax_category, quantity: evaluator.line_items_quantity)
|
36
|
+
order.line_items.reload
|
37
|
+
|
38
|
+
create(:avalara_shipment, order: order, cost: evaluator.shipment_cost, tax_included: evaluator.tax_included)
|
39
|
+
order.shipments.reload
|
40
|
+
|
41
|
+
order.update!
|
42
|
+
order.next
|
43
|
+
end
|
44
|
+
|
45
|
+
factory :completed_avalara_order do
|
46
|
+
shipment_state 'shipped'
|
47
|
+
payment_state 'paid'
|
48
|
+
|
49
|
+
after(:create) do |order|
|
50
|
+
# order.refresh_shipment_rates
|
51
|
+
order.update_column(:completed_at, Time.now)
|
52
|
+
order.update_column(:state, 'complete')
|
53
|
+
payment = create(:credit_card_payment, amount: order.total, order: order, state: 'completed')
|
54
|
+
|
55
|
+
order.update!
|
56
|
+
order.next
|
57
|
+
|
58
|
+
payment.avalara_finalize
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
FactoryGirl.define do
|
2
|
+
factory :avalara_shipment, class: Spree::Shipment do
|
3
|
+
tracking 'U10000'
|
4
|
+
cost BigDecimal.new(10)
|
5
|
+
state 'pending'
|
6
|
+
order
|
7
|
+
stock_location
|
8
|
+
|
9
|
+
transient do
|
10
|
+
tax_included false
|
11
|
+
end
|
12
|
+
|
13
|
+
after(:create) do |shipment, evalulator|
|
14
|
+
shipment.add_shipping_method(create(:avalara_shipping_method, tax_included: evalulator.tax_included), true)
|
15
|
+
|
16
|
+
shipment.order.line_items.each do |line_item|
|
17
|
+
line_item.quantity.times do
|
18
|
+
shipment.inventory_units.create(
|
19
|
+
order_id: shipment.order_id,
|
20
|
+
variant_id: line_item.variant_id,
|
21
|
+
line_item_id: line_item.id
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
FactoryGirl.define do
|
2
|
+
factory :avalara_shipping_method, class: Spree::ShippingMethod do
|
3
|
+
zones { |a| [Spree::Zone.find_by(name: 'GlobalZone') || create(:zone, :with_country, default_tax: true)] }
|
4
|
+
name 'Avalara Ground'
|
5
|
+
code 'Avalara_Ground'
|
6
|
+
association(:calculator, factory: :shipping_calculator, strategy: :create)
|
7
|
+
|
8
|
+
transient do
|
9
|
+
tax_included false
|
10
|
+
end
|
11
|
+
|
12
|
+
before(:create) do |shipping_method, evaluator|
|
13
|
+
if Spree::Country.count == 0
|
14
|
+
create(:country)
|
15
|
+
end
|
16
|
+
shipping_tax_rate = create(:shipping_tax_rate, included_in_price: evaluator.tax_included)
|
17
|
+
shipping_method.tax_category = shipping_tax_rate.tax_category
|
18
|
+
if shipping_method.shipping_categories.empty?
|
19
|
+
shipping_method.shipping_categories << (Spree::ShippingCategory.first || create(:shipping_category))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
FactoryGirl.define do
|
2
|
+
factory :clothing_tax_rate, class: Spree::TaxRate do
|
3
|
+
name 'Tax'
|
4
|
+
amount 0.0
|
5
|
+
tax_category { Spree::TaxCategory.find_by(tax_code: 'PC030000') || create(:tax_category) }
|
6
|
+
association(:calculator, factory: :avalara_transaction_calculator)
|
7
|
+
zone { Spree::Zone.find_or_create_by(name: 'GlobalZone') }
|
8
|
+
show_rate_in_label false
|
9
|
+
end
|
10
|
+
|
11
|
+
factory :shipping_tax_rate, class: Spree::TaxRate do
|
12
|
+
name 'Shipping Tax'
|
13
|
+
amount 0.0
|
14
|
+
tax_category { Spree::TaxCategory.find_by(tax_code: 'FR000000') || create(:tax_category, tax_code: 'FR000000') }
|
15
|
+
association(:calculator, factory: :avalara_transaction_calculator)
|
16
|
+
zone { Spree::Zone.find_or_create_by(name: 'GlobalZone') }
|
17
|
+
show_rate_in_label false
|
18
|
+
end
|
19
|
+
end
|