spree_avatax_official 1.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.env-sample +4 -0
- data/.gitignore +22 -0
- data/.rspec +3 -0
- data/.rubocop.yml +77 -0
- data/.travis.yml +78 -0
- data/Appraisals +49 -0
- data/Gemfile +16 -0
- data/LICENSE +26 -0
- data/README.md +173 -0
- data/Rakefile +21 -0
- data/app/controllers/spree/admin/avalara_entity_use_codes_controller.rb +61 -0
- data/app/controllers/spree/admin/avatax_pings_controller.rb +19 -0
- data/app/controllers/spree/admin/avatax_settings_controller.rb +26 -0
- data/app/controllers/spree/admin/users_controller_decorator.rb +27 -0
- data/app/helpers/spree_avatax_official/http_helper.rb +17 -0
- data/app/helpers/spree_avatax_official/tax_adjustment_label_helper.rb +30 -0
- data/app/models/avatax/request_decorator.rb +34 -0
- data/app/models/spree_avatax_official/avatax_log.rb +57 -0
- data/app/models/spree_avatax_official/calculator/avatax_transaction_calculator.rb +28 -0
- data/app/models/spree_avatax_official/configuration.rb +20 -0
- data/app/models/spree_avatax_official/entity_use_code.rb +7 -0
- data/app/models/spree_avatax_official/has_uuid.rb +22 -0
- data/app/models/spree_avatax_official/spree/address_decorator.rb +31 -0
- data/app/models/spree_avatax_official/spree/inventory_unit_decorator.rb +11 -0
- data/app/models/spree_avatax_official/spree/line_item_decorator.rb +27 -0
- data/app/models/spree_avatax_official/spree/order_decorator.rb +91 -0
- data/app/models/spree_avatax_official/spree/refund_decorator.rb +22 -0
- data/app/models/spree_avatax_official/spree/shipment_decorator.rb +25 -0
- data/app/models/spree_avatax_official/spree/tax_category_decorator.rb +14 -0
- data/app/models/spree_avatax_official/spree/user_decorator.rb +11 -0
- data/app/models/spree_avatax_official/transaction.rb +27 -0
- data/app/overrides/spree/admin/shared/sub_menu/_configuration.rb +10 -0
- data/app/overrides/spree/admin/sidebar.rb +14 -0
- data/app/presenters/spree_avatax_official/address_presenter.rb +40 -0
- data/app/presenters/spree_avatax_official/item_presenter.rb +92 -0
- data/app/presenters/spree_avatax_official/ship_to_address_presenter.rb +22 -0
- data/app/presenters/spree_avatax_official/transactions/adjust_presenter.rb +31 -0
- data/app/presenters/spree_avatax_official/transactions/create_presenter.rb +80 -0
- data/app/presenters/spree_avatax_official/transactions/full_refund_presenter.rb +32 -0
- data/app/presenters/spree_avatax_official/transactions/partial_refund_presenter.rb +46 -0
- data/app/services/spree_avatax_official/address/validate.rb +27 -0
- data/app/services/spree_avatax_official/base.rb +71 -0
- data/app/services/spree_avatax_official/create_tax_adjustments_service.rb +133 -0
- data/app/services/spree_avatax_official/generate_transaction_cache_key_service.rb +94 -0
- data/app/services/spree_avatax_official/get_tax_service.rb +20 -0
- data/app/services/spree_avatax_official/settings/update_service.rb +36 -0
- data/app/services/spree_avatax_official/transactions/adjust_service.rb +36 -0
- data/app/services/spree_avatax_official/transactions/create_service.rb +47 -0
- data/app/services/spree_avatax_official/transactions/find_order_transaction_service.rb +23 -0
- data/app/services/spree_avatax_official/transactions/full_refund_service.rb +36 -0
- data/app/services/spree_avatax_official/transactions/get_by_code_service.rb +32 -0
- data/app/services/spree_avatax_official/transactions/partial_refund_service.rb +33 -0
- data/app/services/spree_avatax_official/transactions/refund_service.rb +87 -0
- data/app/services/spree_avatax_official/transactions/void_service.rb +28 -0
- data/app/services/spree_avatax_official/utilities/ping_service.rb +9 -0
- data/app/views/spree/admin/avalara_entity_use_codes/_form.html.erb +20 -0
- data/app/views/spree/admin/avalara_entity_use_codes/edit.html.erb +12 -0
- data/app/views/spree/admin/avalara_entity_use_codes/index.html.erb +35 -0
- data/app/views/spree/admin/avalara_entity_use_codes/new.html.erb +12 -0
- data/app/views/spree/admin/avatax_settings/edit.html.erb +99 -0
- data/app/views/spree/admin/users/avalara_information.html.erb +39 -0
- data/app/views/spree/admin/zones/_form.html.erb +58 -0
- data/bin/rails +8 -0
- data/config/initializers/spree_permitted_attributes.rb +5 -0
- data/config/locales/en.yml +40 -0
- data/config/routes.rb +15 -0
- data/db/migrate/20190118155953_add_exemption_number_to_spree_users.rb +7 -0
- data/db/migrate/20190118160653_create_spree_avalara_entity_use_codes.rb +11 -0
- data/db/migrate/20190118161318_add_avalara_entity_use_code_reference_to_users.rb +7 -0
- data/db/migrate/20190118162345_add_vat_id_to_spree_users.rb +7 -0
- data/db/migrate/20190122154119_create_spree_avatax_official_transactions.rb +10 -0
- data/db/migrate/20190201123706_add_tax_code_to_spree_tax_categories.rb +7 -0
- data/db/migrate/20190208130136_add_avatax_company_code_to_spree_stores.rb +8 -0
- data/db/migrate/20190225145808_add_uuid_to_spree_line_items_and_spree_shipments.rb +13 -0
- data/db/migrate/20190329071439_add_included_in_price_to_spree_zones.rb +5 -0
- data/db/migrate/20191001085458_remove_spree_avalara_entity_use_codes_table.rb +12 -0
- data/db/migrate/20191001092353_create_spree_avatax_official_entity_use_codes_table.rb +18 -0
- data/db/seeds.rb +1 -0
- data/gemfiles/spree_3_1.gemfile +16 -0
- data/gemfiles/spree_3_7.gemfile +13 -0
- data/gemfiles/spree_4_0.gemfile +14 -0
- data/gemfiles/spree_4_1.gemfile +14 -0
- data/gemfiles/spree_4_2.gemfile +14 -0
- data/gemfiles/spree_master.gemfile +14 -0
- data/lib/generators/spree_avatax_official/install/install_generator.rb +38 -0
- data/lib/generators/spree_avatax_official/install/templates/config/initializers/spree_avatax_official.rb +9 -0
- data/lib/spree_avatax_official.rb +5 -0
- data/lib/spree_avatax_official/engine.rb +32 -0
- data/lib/spree_avatax_official/factories.rb +9 -0
- data/lib/spree_avatax_official/seeder.rb +51 -0
- data/lib/spree_avatax_official/version.rb +11 -0
- data/lib/tasks/load_seeds.rake +6 -0
- data/spec/.rubocop.yml +36 -0
- data/spec/factories/canada_address_factory.rb +23 -0
- data/spec/factories/europe_address_factory.rb +22 -0
- data/spec/factories/spree/avatax_global_zone_factory.rb +16 -0
- data/spec/factories/spree/avatax_order_factory.rb +69 -0
- data/spec/factories/spree/avatax_shipment_factory.rb +31 -0
- data/spec/factories/spree/avatax_shipping_method_factory.rb +35 -0
- data/spec/factories/spree/avatax_tax_category_factory.rb +17 -0
- data/spec/factories/spree/avatax_tax_rate_factory.rb +23 -0
- data/spec/factories/spree/line_item_factory.rb +13 -0
- data/spec/factories/spree/promotion_factory.rb +35 -0
- data/spec/factories/spree/shipping_calculator_factory.rb +10 -0
- data/spec/factories/spree_avatax_official/avalara_entity_use_code_factory.rb +7 -0
- data/spec/factories/spree_avatax_official/calculator/avatax_transaction_calculator_factory.rb +3 -0
- data/spec/factories/spree_avatax_official/transaction_factory.rb +12 -0
- data/spec/factories/usa_address_factory.rb +34 -0
- data/spec/features/admin/edit_avatax_settings_spec.rb +11 -0
- data/spec/features/admin/update_avatax_settings_spec.rb +200 -0
- data/spec/features/spree/admin/avalara_entity_use_codes_controller_spec.rb +71 -0
- data/spec/features/spree/admin/users_controller_spec.rb +34 -0
- data/spec/helpers/spree_avatax_official/tax_adjustment_label_helper_spec.rb +81 -0
- data/spec/lib/spree_avatax_official/seeder_spec.rb +23 -0
- data/spec/models/spree/line_item_spec.rb +76 -0
- data/spec/models/spree/order_spec.rb +210 -0
- data/spec/models/spree/shipment_spec.rb +11 -0
- data/spec/models/spree_avatax_official/avatax_log_spec.rb +87 -0
- data/spec/models/spree_avatax_official/entity_use_code_spec.rb +9 -0
- data/spec/models/spree_avatax_official/has_uuid_spec.rb +21 -0
- data/spec/models/spree_avatax_official/spree/refund_decorator_spec.rb +31 -0
- data/spec/models/spree_avatax_official/transaction_spec.rb +9 -0
- data/spec/presenters/spree_avatax_official/address_presenter_spec.rb +53 -0
- data/spec/presenters/spree_avatax_official/item_presenter_spec.rb +159 -0
- data/spec/presenters/spree_avatax_official/ship_to_address_presenter_spec.rb +34 -0
- data/spec/presenters/spree_avatax_official/transactions/adjust_presenter_spec.rb +39 -0
- data/spec/presenters/spree_avatax_official/transactions/create_presenter_spec.rb +110 -0
- data/spec/presenters/spree_avatax_official/transactions/full_refund_presenter_spec.rb +30 -0
- data/spec/presenters/spree_avatax_official/transactions/partial_refund_presenter_spec.rb +48 -0
- data/spec/services/spree_avatax_official/address/validate_spec.rb +47 -0
- data/spec/services/spree_avatax_official/create_tax_adjustments_service_spec.rb +444 -0
- data/spec/services/spree_avatax_official/generate_transaction_cache_key_service_spec.rb +29 -0
- data/spec/services/spree_avatax_official/get_tax_service_spec.rb +33 -0
- data/spec/services/spree_avatax_official/settings/update_service_spec.rb +131 -0
- data/spec/services/spree_avatax_official/transactions/adjust_service_spec.rb +55 -0
- data/spec/services/spree_avatax_official/transactions/create_service_spec.rb +262 -0
- data/spec/services/spree_avatax_official/transactions/find_order_transaction_service_spec.rb +38 -0
- data/spec/services/spree_avatax_official/transactions/full_refund_service_spec.rb +24 -0
- data/spec/services/spree_avatax_official/transactions/get_by_code_service_spec.rb +74 -0
- data/spec/services/spree_avatax_official/transactions/partial_refund_service_spec.rb +33 -0
- data/spec/services/spree_avatax_official/transactions/refund_service_spec.rb +65 -0
- data/spec/services/spree_avatax_official/transactions/void_service_spec.rb +33 -0
- data/spec/services/spree_avatax_official/utilities/ping_service_spec.rb +35 -0
- data/spec/spec_helper.rb +104 -0
- data/spec/support/avatax.rb +15 -0
- data/spec/support/capybara.rb +21 -0
- data/spec/support/database_cleaner.rb +25 -0
- data/spec/support/factory_bot.rb +9 -0
- data/spec/support/vcr.rb +17 -0
- data/spec/vcr/SpreeAvataxOfficial_Transactions_FindOrderTransactionService/_call/with_Spree_Order/when_order_does_NOT_have_a_SalesInvoice_transaction/when_transaction_does_NOT_exist_in_avatax/returns_failure.yml +44 -0
- data/spec/vcr/SpreeAvataxOfficial_Transactions_FindOrderTransactionService/_call/with_Spree_Order/when_order_does_NOT_have_a_SalesInvoice_transaction/when_transaction_exists_in_avatax/returns_success_and_creates_a_new_SalesInvoice_transaction.yml +48 -0
- data/spec/vcr/spree_avatax_official/address/validate_failure.yml +46 -0
- data/spec/vcr/spree_avatax_official/address/validate_success.yml +43 -0
- data/spec/vcr/spree_avatax_official/address/zipcode_failure.yml +45 -0
- data/spec/vcr/spree_avatax_official/create_tax_adjustments/californian_stock_location.yml +60 -0
- data/spec/vcr/spree_avatax_official/create_tax_adjustments/completed_order_line_item_update.yml +62 -0
- data/spec/vcr/spree_avatax_official/create_tax_adjustments/order_adjustment_promotion.yml +61 -0
- data/spec/vcr/spree_avatax_official/create_tax_adjustments/shipment_adjustment_promotion.yml +60 -0
- data/spec/vcr/spree_avatax_official/create_tax_adjustments/simple_completed_order.yml +60 -0
- data/spec/vcr/spree_avatax_official/create_tax_adjustments/tax_excluded/line_item_adjustment_promotion.yml +59 -0
- data/spec/vcr/spree_avatax_official/create_tax_adjustments/tax_excluded/line_item_and_shipment.yml +60 -0
- data/spec/vcr/spree_avatax_official/create_tax_adjustments/tax_excluded/multiple_line_items_multiple_quantity.yml +59 -0
- data/spec/vcr/spree_avatax_official/create_tax_adjustments/tax_excluded/single_line_item.yml +55 -0
- data/spec/vcr/spree_avatax_official/create_tax_adjustments/tax_included/line_item_adjustment_promotion.yml +59 -0
- data/spec/vcr/spree_avatax_official/create_tax_adjustments/tax_included/line_item_and_shipment.yml +60 -0
- data/spec/vcr/spree_avatax_official/create_tax_adjustments/tax_included/multiple_line_items_multiple_quantity.yml +59 -0
- data/spec/vcr/spree_avatax_official/create_tax_adjustments/tax_included/single_line_item.yml +55 -0
- data/spec/vcr/spree_avatax_official/create_tax_adjustments/with_incorrect_address.yml +97 -0
- data/spec/vcr/spree_avatax_official/get_tax/error.yml +49 -0
- data/spec/vcr/spree_avatax_official/get_tax/sucsess.yml +55 -0
- data/spec/vcr/spree_avatax_official/transactions/adjust/failure.yml +101 -0
- data/spec/vcr/spree_avatax_official/transactions/adjust/invoice_order_success.yml +117 -0
- data/spec/vcr/spree_avatax_official/transactions/create/complete_order_success.yml +60 -0
- data/spec/vcr/spree_avatax_official/transactions/create/gst/canada_to_canada.yml +55 -0
- data/spec/vcr/spree_avatax_official/transactions/create/gst/canada_to_us.yml +57 -0
- data/spec/vcr/spree_avatax_official/transactions/create/gst/us_to_canada.yml +56 -0
- data/spec/vcr/spree_avatax_official/transactions/create/invoice_order_success.yml +60 -0
- data/spec/vcr/spree_avatax_official/transactions/create/sales_order_success.yml +60 -0
- data/spec/vcr/spree_avatax_official/transactions/create/timeout.yml +54 -0
- data/spec/vcr/spree_avatax_official/transactions/create/vat/europe_to_europe.yml +57 -0
- data/spec/vcr/spree_avatax_official/transactions/create/vat/europe_to_us.yml +57 -0
- data/spec/vcr/spree_avatax_official/transactions/create/vat/us_to_europe.yml +58 -0
- data/spec/vcr/spree_avatax_official/transactions/get_by_code/error.yml +44 -0
- data/spec/vcr/spree_avatax_official/transactions/get_by_code/order_with_custom_code_success.yml +49 -0
- data/spec/vcr/spree_avatax_official/transactions/get_by_code/order_with_number_success.yml +49 -0
- data/spec/vcr/spree_avatax_official/transactions/get_by_code/order_with_type_success.yml +48 -0
- data/spec/vcr/spree_avatax_official/transactions/get_by_code/order_without_type_success.yml +48 -0
- data/spec/vcr/spree_avatax_official/transactions/refund/full_refund_success.yml +114 -0
- data/spec/vcr/spree_avatax_official/transactions/refund/partial_refund_success.yml +58 -0
- data/spec/vcr/spree_avatax_official/transactions/refund/partial_refund_with_refund_success.yml +58 -0
- data/spec/vcr/spree_avatax_official/transactions/void/success.yml +112 -0
- data/spec/vcr/spree_avatax_official/utilities/ping.yml +41 -0
- data/spec/vcr/spree_avatax_official/utilities/ping_unauthorized.yml +42 -0
- data/spec/vcr/spree_line_item/update_tax_charge/decrease_quantity.yml +55 -0
- data/spec/vcr/spree_line_item/update_tax_charge/increase_quantity.yml +55 -0
- data/spec/vcr/spree_order/california_order.yml +67 -0
- data/spec/vcr/spree_order/complete_order.yml +60 -0
- data/spec/vcr/spree_order/order_transition_to_completed.yml +112 -0
- data/spec/vcr/spree_order/order_with_line_item_adjustment.yml +57 -0
- data/spec/vcr/spree_order/order_with_order_adjustment.yml +57 -0
- data/spec/vcr/spree_order/simple_order_with_single_line_item.yml +55 -0
- data/spec/vcr/spree_order/simple_order_with_single_line_item_and_shipment.yml +57 -0
- data/spec/vcr/spree_order/update_tax_charge/create_line_item.yml +55 -0
- data/spree_avatax_official.gemspec +43 -0
- metadata +486 -0
@@ -0,0 +1,36 @@
|
|
1
|
+
module SpreeAvataxOfficial
|
2
|
+
module Transactions
|
3
|
+
class AdjustService < SpreeAvataxOfficial::Base
|
4
|
+
def call(order:, adjustment_reason:, adjustment_description: '', options: {})
|
5
|
+
response = send_request(order, adjustment_reason, adjustment_description, options)
|
6
|
+
|
7
|
+
request_result(response, order) do
|
8
|
+
if order.avatax_sales_invoice_transaction.nil?
|
9
|
+
create_transaction!(
|
10
|
+
order: order
|
11
|
+
)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def send_request(order, adjustment_reason, adjustment_description, options) # rubocop:disable Metrics/MethodLength
|
19
|
+
adjust_transaction_model = SpreeAvataxOfficial::Transactions::AdjustPresenter.new(
|
20
|
+
order: order,
|
21
|
+
adjustment_reason: adjustment_reason,
|
22
|
+
adjustment_description: adjustment_description
|
23
|
+
).to_json
|
24
|
+
|
25
|
+
logger.info(adjust_transaction_model)
|
26
|
+
|
27
|
+
client.adjust_transaction(
|
28
|
+
company_code(order),
|
29
|
+
order.number,
|
30
|
+
adjust_transaction_model,
|
31
|
+
options
|
32
|
+
)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module SpreeAvataxOfficial
|
2
|
+
module Transactions
|
3
|
+
class CreateService < SpreeAvataxOfficial::Base
|
4
|
+
def call(order:, options: {}) # rubocop:disable Metrics/MethodLength
|
5
|
+
return failure(false) unless can_send_order_to_avatax?(order)
|
6
|
+
|
7
|
+
transaction_type = choose_transaction_type(order)
|
8
|
+
response = send_request(order, transaction_type, options)
|
9
|
+
|
10
|
+
request_result(response, order) do
|
11
|
+
if order.completed? && response.body['id'].to_i.positive?
|
12
|
+
create_transaction!(
|
13
|
+
order: order,
|
14
|
+
transaction_type: transaction_type
|
15
|
+
)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def can_send_order_to_avatax?(order)
|
23
|
+
# We need to ensure that order would not be commited multiple of times
|
24
|
+
order.avatax_tax_calculation_required? && order.avatax_sales_invoice_transaction.blank?
|
25
|
+
end
|
26
|
+
|
27
|
+
def choose_transaction_type(order)
|
28
|
+
if order.completed?
|
29
|
+
SpreeAvataxOfficial::Transaction::SALES_INVOICE
|
30
|
+
else
|
31
|
+
SpreeAvataxOfficial::Transaction::SALES_ORDER
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def send_request(order, transaction_type, options)
|
36
|
+
create_transaction_model = SpreeAvataxOfficial::Transactions::CreatePresenter.new(
|
37
|
+
order: order,
|
38
|
+
transaction_type: transaction_type
|
39
|
+
).to_json
|
40
|
+
|
41
|
+
logger.info(create_transaction_model)
|
42
|
+
|
43
|
+
client.create_transaction(create_transaction_model, options)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module SpreeAvataxOfficial
|
2
|
+
module Transactions
|
3
|
+
class FindOrderTransactionService < SpreeAvataxOfficial::Base
|
4
|
+
def call(order:)
|
5
|
+
return success(true) if order.avatax_sales_invoice_transaction.present?
|
6
|
+
return failure(false) if get_transaction(order).failure?
|
7
|
+
|
8
|
+
order.create_avatax_sales_invoice_transaction(code: order.number)
|
9
|
+
|
10
|
+
# ensure taxable items have avatax_uuid
|
11
|
+
order.taxable_items.each { |item| item.update(avatax_uuid: SecureRandom.uuid) }
|
12
|
+
|
13
|
+
success(true)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def get_transaction(order)
|
19
|
+
SpreeAvataxOfficial::Transactions::GetByCodeService.call(order: order)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module SpreeAvataxOfficial
|
2
|
+
module Transactions
|
3
|
+
class FullRefundService < SpreeAvataxOfficial::Base
|
4
|
+
def call(order:, transaction_code:)
|
5
|
+
create_refund(order, transaction_code).tap do |response|
|
6
|
+
return request_result(response, order) do
|
7
|
+
create_transaction!(
|
8
|
+
code: response.body['code'],
|
9
|
+
order: order,
|
10
|
+
transaction_type: SpreeAvataxOfficial::Transaction::RETURN_INVOICE
|
11
|
+
)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def create_refund(order, transaction_code)
|
19
|
+
logger.info(refund_model(order, transaction_code))
|
20
|
+
|
21
|
+
client.refund_transaction(
|
22
|
+
company_code(order),
|
23
|
+
order.number,
|
24
|
+
refund_model(order, transaction_code)
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
def refund_model(order, transaction_code)
|
29
|
+
@refund_model ||= FullRefundPresenter.new(
|
30
|
+
order: order,
|
31
|
+
transaction_code: transaction_code
|
32
|
+
).to_json
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module SpreeAvataxOfficial
|
2
|
+
module Transactions
|
3
|
+
class GetByCodeService < SpreeAvataxOfficial::Base
|
4
|
+
def call(order:, type: 'SalesInvoice', code: nil)
|
5
|
+
code ||= transaction_code(order, type)
|
6
|
+
|
7
|
+
return failure(::Spree.t('spree_avatax_official.get_by_code_service.missing_code')) if code.nil?
|
8
|
+
|
9
|
+
request_result(get_by_code(code, order), order)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def get_by_code(code, order)
|
15
|
+
logger.info(code)
|
16
|
+
|
17
|
+
client.get_transaction_by_code(
|
18
|
+
company_code(order),
|
19
|
+
code
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
def transaction_code(order, type)
|
24
|
+
transaction = order
|
25
|
+
.avatax_transactions
|
26
|
+
.find_by(transaction_type: type)
|
27
|
+
|
28
|
+
transaction.try(:code) || order.number
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module SpreeAvataxOfficial
|
2
|
+
module Transactions
|
3
|
+
class PartialRefundService < SpreeAvataxOfficial::Base
|
4
|
+
def call(order:, transaction_code:, refund_items:)
|
5
|
+
response = send_request(order, transaction_code, refund_items)
|
6
|
+
|
7
|
+
request_result(response, order) do
|
8
|
+
unless response.body['id'].to_i.zero?
|
9
|
+
create_transaction!(
|
10
|
+
code: response.body['code'],
|
11
|
+
order: order,
|
12
|
+
transaction_type: SpreeAvataxOfficial::Transaction::RETURN_INVOICE
|
13
|
+
)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def send_request(order, transaction_code, refund_items)
|
21
|
+
refund_transaction_model = SpreeAvataxOfficial::Transactions::PartialRefundPresenter.new(
|
22
|
+
order: order,
|
23
|
+
refund_items: refund_items,
|
24
|
+
transaction_code: transaction_code
|
25
|
+
).to_json
|
26
|
+
|
27
|
+
logger.info(refund_transaction_model)
|
28
|
+
|
29
|
+
client.create_transaction(refund_transaction_model)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module SpreeAvataxOfficial
|
2
|
+
module Transactions
|
3
|
+
class RefundService < SpreeAvataxOfficial::Base
|
4
|
+
def call(refundable:)
|
5
|
+
if full_refund?(refundable)
|
6
|
+
create_full_refund(refundable)
|
7
|
+
else
|
8
|
+
create_partial_refund(refundable)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def full_refund?(refundable)
|
15
|
+
refundable.order_inventory_units == inventory_units(refundable)
|
16
|
+
end
|
17
|
+
|
18
|
+
def refundable_class(refundable)
|
19
|
+
@refundable_class ||= refundable.class.name.demodulize
|
20
|
+
end
|
21
|
+
|
22
|
+
def inventory_units(refundable)
|
23
|
+
@inventory_units ||= case refundable_class(refundable)
|
24
|
+
when 'ReturnAuthorization'
|
25
|
+
refundable.inventory_units
|
26
|
+
when 'Refund'
|
27
|
+
refundable.reimbursement.return_items.map(&:inventory_unit)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def create_partial_refund(refundable)
|
32
|
+
SpreeAvataxOfficial::Transactions::PartialRefundService.call(
|
33
|
+
**refundable_params(refundable).merge(
|
34
|
+
refund_items: refund_items(refundable)
|
35
|
+
)
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
def refund_items(refundable)
|
40
|
+
inventory_units(refundable).group_by(&:line_item).reduce({}) do |ids, (line_item, units)|
|
41
|
+
ids.merge!(line_item => [line_item_quantity(units), -1 * line_item_amount(refundable, units)])
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def refundable_params(refundable)
|
46
|
+
{
|
47
|
+
order: refundable.order,
|
48
|
+
transaction_code: refund_transaction_code(refundable.order_number, refundable.id)
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
def line_item_quantity(units)
|
53
|
+
return units.count unless units.first.respond_to?(:quantity)
|
54
|
+
|
55
|
+
units.sum(&:quantity)
|
56
|
+
end
|
57
|
+
|
58
|
+
def line_item_amount(refundable, units)
|
59
|
+
case refundable_class(refundable)
|
60
|
+
when 'ReturnAuthorization'
|
61
|
+
amount_per_unit(refundable, units) * units.count
|
62
|
+
when 'Refund'
|
63
|
+
items(refundable, units).sum(&:pre_tax_amount)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def amount_per_unit(refundable, units)
|
68
|
+
items(refundable, units).sum(&:pre_tax_amount) / items(refundable, units).sum(&:quantity)
|
69
|
+
end
|
70
|
+
|
71
|
+
def items(refundable, units)
|
72
|
+
case refundable_class(refundable)
|
73
|
+
when 'ReturnAuthorization'
|
74
|
+
units.map(&:line_item).uniq
|
75
|
+
when 'Refund'
|
76
|
+
units.flat_map(&:return_items).uniq
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def create_full_refund(refundable)
|
81
|
+
SpreeAvataxOfficial::Transactions::FullRefundService.call(
|
82
|
+
refundable_params(refundable)
|
83
|
+
)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module SpreeAvataxOfficial
|
2
|
+
module Transactions
|
3
|
+
class VoidService < SpreeAvataxOfficial::Base
|
4
|
+
def call(order:, options: {})
|
5
|
+
if order.avatax_sales_invoice_transaction.blank?
|
6
|
+
return failure(::Spree.t('spree_avatax_official.void_service.missing_sales_invoice_transaction'))
|
7
|
+
end
|
8
|
+
|
9
|
+
response = send_request(order, options)
|
10
|
+
|
11
|
+
request_result(response, order)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def send_request(order, options)
|
17
|
+
logger.info(options, order)
|
18
|
+
|
19
|
+
client.void_transaction(
|
20
|
+
company_code(order),
|
21
|
+
order.number,
|
22
|
+
{ code: 'DocVoided' },
|
23
|
+
options
|
24
|
+
)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<div>
|
2
|
+
<div class="form-group">
|
3
|
+
<%= f.field_container :code do %>
|
4
|
+
<%= f.label :code %>
|
5
|
+
<%= f.text_field :code, class: 'form-control' %>
|
6
|
+
<% end %>
|
7
|
+
</div>
|
8
|
+
<div class="form-group">
|
9
|
+
<%= f.field_container :name do %>
|
10
|
+
<%= f.label :name %>
|
11
|
+
<%= f.text_field :name, class: 'form-control' %>
|
12
|
+
<% end %>
|
13
|
+
</div>
|
14
|
+
<div class="form-group">
|
15
|
+
<%= f.field_container :description do %>
|
16
|
+
<%= f.label :description %>
|
17
|
+
<%= f.text_area :description, class: 'form-control' %>
|
18
|
+
<% end %>
|
19
|
+
</div>
|
20
|
+
</div>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<% content_for :page_title do %>
|
2
|
+
<%= Spree.t('avalara_entity_use_codes') %>
|
3
|
+
<% end %>
|
4
|
+
|
5
|
+
<%= render 'spree/shared/error_messages', target: @use_code %>
|
6
|
+
|
7
|
+
<%= form_for @use_code, url: admin_avalara_entity_use_code_path(@use_code), method: :put do |f| %>
|
8
|
+
<fieldset>
|
9
|
+
<%= render partial: 'form', locals: { f: f } %>
|
10
|
+
<%= render partial: 'spree/admin/shared/edit_resource_links', locals: { collection_url: admin_avalara_entity_use_codes_path } %>
|
11
|
+
</fieldset>
|
12
|
+
<% end %>
|
@@ -0,0 +1,35 @@
|
|
1
|
+
<% content_for :page_title do %>
|
2
|
+
<%= Spree.t('spree_avatax_official.avalara_entity_use_code_settings') %>
|
3
|
+
<% end %>
|
4
|
+
|
5
|
+
<% content_for :page_actions do %>
|
6
|
+
<%= button_link_to Spree.t('spree_avatax_official.avalara entity_use_code'),
|
7
|
+
new_admin_avalara_entity_use_code_url,
|
8
|
+
class: 'btn-success',
|
9
|
+
icon: 'add',
|
10
|
+
id: 'admin_new_avalara_entity_use_code_link' %>
|
11
|
+
<% end %>
|
12
|
+
|
13
|
+
<table class="table" id="listing_sale_events" data-hook>
|
14
|
+
<thead>
|
15
|
+
<tr data-hook="admin_sale_events_index_headers">
|
16
|
+
<th><%= Spree.t(:code) %></th>
|
17
|
+
<th><%= Spree.t(:name) %></th>
|
18
|
+
<th><%= Spree.t(:description) %></th>
|
19
|
+
<th data-hook="admin_sale_events_index_header_actions"></th>
|
20
|
+
</tr>
|
21
|
+
</thead>
|
22
|
+
<tbody>
|
23
|
+
<% @use_codes.each do |use_code| %>
|
24
|
+
<tr id="<%= dom_id use_code %>" data-hook="admin_sale_events_index_rows">
|
25
|
+
<td><%= use_code.code %></td>
|
26
|
+
<td><%= use_code.name %></td>
|
27
|
+
<td><%= use_code.description %></td>
|
28
|
+
<td data-hook="admin_avalara_entity_use_codes_index_row_actions">
|
29
|
+
<%= link_to_edit(use_code, url: edit_admin_avalara_entity_use_code_path(use_code)) %>
|
30
|
+
<%= link_to_delete(use_code, { url: admin_avalara_entity_use_code_path(use_code) }) %>
|
31
|
+
</td>
|
32
|
+
</tr>
|
33
|
+
<% end %>
|
34
|
+
</tbody>
|
35
|
+
</table>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<% content_for :page_title do %>
|
2
|
+
<%= Spree.t('avalara_entity_use_codes') %>
|
3
|
+
<% end %>
|
4
|
+
|
5
|
+
<%= render 'spree/shared/error_messages', target: @use_code %>
|
6
|
+
|
7
|
+
<%= form_for @use_code, url: admin_avalara_entity_use_codes_path, html: { multipart: true } do |f| %>
|
8
|
+
<fieldset>
|
9
|
+
<%= render partial: 'form', locals: { f: f } %>
|
10
|
+
<%= render partial: 'spree/admin/shared/new_resource_links', locals: { collection_url: admin_avalara_entity_use_codes_path } %>
|
11
|
+
</fieldset>
|
12
|
+
<% end %>
|
@@ -0,0 +1,99 @@
|
|
1
|
+
<h1><%= Spree.t('spree_avatax_official.settings') %></h1>
|
2
|
+
|
3
|
+
<%= form_tag(admin_avatax_settings_path, method: :put, id: :avatax_settings_form) do %>
|
4
|
+
|
5
|
+
<div class="yui-g">
|
6
|
+
<div class="yui-u first">
|
7
|
+
<fieldset>
|
8
|
+
<legend><%= Spree.t('spree_avatax_official.enabled') %></legend>
|
9
|
+
<div class="checkbox">
|
10
|
+
<label>
|
11
|
+
<%= hidden_field_tag('enabled', false) %>
|
12
|
+
<%= check_box_tag('enabled', true, SpreeAvataxOfficial::Config.enabled) %>
|
13
|
+
<%= Spree.t('spree_avatax_official.enabled') %>
|
14
|
+
</label>
|
15
|
+
</div>
|
16
|
+
</fieldset>
|
17
|
+
|
18
|
+
<fieldset>
|
19
|
+
<legend><%= Spree.t('spree_avatax_official.avatax_credentials') %></legend>
|
20
|
+
<p>
|
21
|
+
<label><%= Spree.t('spree_avatax_official.company_code') %></label><br />
|
22
|
+
<%= text_field_tag('company_code', SpreeAvataxOfficial::Config.company_code, size: 46, maxlength: 256, class: 'form-control') %>
|
23
|
+
</p>
|
24
|
+
|
25
|
+
<p>
|
26
|
+
<label><%= Spree.t('spree_avatax_official.account_number') %></label><br />
|
27
|
+
<%= text_field_tag('account_number', SpreeAvataxOfficial::Config.account_number, size: 46, maxlength: 256, class: 'form-control') %>
|
28
|
+
</p>
|
29
|
+
<p>
|
30
|
+
<label><%= Spree.t('spree_avatax_official.license_key') %></label><br />
|
31
|
+
<%= text_field_tag('license_key', SpreeAvataxOfficial::Config.license_key, size: 46, maxlength: 256, class: 'form-control') %>
|
32
|
+
</p>
|
33
|
+
</fieldset>
|
34
|
+
|
35
|
+
<fieldset>
|
36
|
+
<legend><%= Spree.t('spree_avatax_official.endpoint_urls') %></legend>
|
37
|
+
<p>
|
38
|
+
<label><%= Spree.t('spree_avatax_official.endpoint') %></label><br />
|
39
|
+
<%= text_field_tag('endpoint', SpreeAvataxOfficial::Config.endpoint, size: 46, maxlength: 256, class: 'form-control') %>
|
40
|
+
</p>
|
41
|
+
</fieldset>
|
42
|
+
|
43
|
+
<fieldset>
|
44
|
+
<legend><%= Spree.t('spree_avatax_official.commit_transaction_enabled') %></legend>
|
45
|
+
<div class="checkbox">
|
46
|
+
<label>
|
47
|
+
<%= hidden_field_tag('commit_transaction_enabled', false) %>
|
48
|
+
<%= check_box_tag('commit_transaction_enabled', true, SpreeAvataxOfficial::Config.commit_transaction_enabled) %>
|
49
|
+
<%= Spree.t('spree_avatax_official.commit_transaction_enabled') %>
|
50
|
+
</label>
|
51
|
+
</div>
|
52
|
+
</fieldset>
|
53
|
+
|
54
|
+
<fieldset>
|
55
|
+
<legend><%= Spree.t('spree_avatax_official.address_validation') %></legend>
|
56
|
+
<div class="checkbox">
|
57
|
+
<label>
|
58
|
+
<%= hidden_field_tag('address_validation_enabled', false) %>
|
59
|
+
<%= check_box_tag('address_validation_enabled', true, SpreeAvataxOfficial::Config.address_validation_enabled) %>
|
60
|
+
<%= Spree.t('spree_avatax_official.enable_address_validation') %>
|
61
|
+
</label>
|
62
|
+
</p>
|
63
|
+
</fieldset>
|
64
|
+
|
65
|
+
<fieldset>
|
66
|
+
<legend><%= Spree.t('spree_avatax_official.ship_from_address') %></legend>
|
67
|
+
<p>
|
68
|
+
<label><%= Spree.t('address1') %></label><br />
|
69
|
+
<%= text_field_tag('ship_from[line1]', @ship_from_address[:line1], size: 46, maxlength: 256, class: 'form-control') %>
|
70
|
+
</p>
|
71
|
+
<p>
|
72
|
+
<label><%= Spree.t('address2') %></label><br />
|
73
|
+
<%= text_field_tag('ship_from[line2]', @ship_from_address[:line2], size: 46, maxlength: 256, class: 'form-control') %>
|
74
|
+
</p>
|
75
|
+
<p>
|
76
|
+
<label><%= Spree.t('city') %></label><br />
|
77
|
+
<%= text_field_tag('ship_from[city]', @ship_from_address[:city], size: 46, maxlength: 256, class: 'form-control') %>
|
78
|
+
</p>
|
79
|
+
<p>
|
80
|
+
<label><%= Spree.t('country') %></label><br />
|
81
|
+
<%= select_tag('ship_from[country]', options_from_collection_for_select(Spree::Country.all, 'iso3', 'name', selected: @country.try(:iso3)), class: 'select2') %>
|
82
|
+
</p>
|
83
|
+
<% if @states.present? && @states.any? %>
|
84
|
+
<p>
|
85
|
+
<label><%= Spree.t('state') %></label><br />
|
86
|
+
<%= select_tag('ship_from[region]', options_from_collection_for_select(@states, 'abbr', 'name', selected: @ship_from_address[:region]), class: 'select2') %>
|
87
|
+
</p>
|
88
|
+
<% end %>
|
89
|
+
<p>
|
90
|
+
<label><%= Spree.t('postalcode') %></label><br />
|
91
|
+
<%= text_field_tag('ship_from[postal_code]', @ship_from_address[:postalCode], size: 46, maxlength: 25, class: 'form-control') %>
|
92
|
+
</p>
|
93
|
+
</fieldset>
|
94
|
+
</div>
|
95
|
+
</div>
|
96
|
+
|
97
|
+
<p class="form-buttons"><%= button Spree.t('spree_avatax_official.save_preferences') %></p>
|
98
|
+
<p class="form-buttons"><%=link_to Spree.t('spree_avatax_official.ping_avatax'), :admin_avatax_ping, method: :post, class: 'btn btn-primary' %></p>
|
99
|
+
<% end %>
|