solidus_legacy_return_authorizations 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +10 -0
  5. data/LICENSE +26 -0
  6. data/README.md +62 -0
  7. data/Rakefile +21 -0
  8. data/app/assets/javascripts/spree/backend/solidus_legacy_return_authorizations.js +2 -0
  9. data/app/assets/stylesheets/spree/backend/solidus_legacy_return_authorizations.css +4 -0
  10. data/app/controllers/spree/admin/legacy_return_authorizations_controller.rb +25 -0
  11. data/app/controllers/spree/api/legacy_return_authorizations_controller.rb +74 -0
  12. data/app/helpers/spree/admin/navigation_helper_decorator.rb +12 -0
  13. data/app/helpers/spree/api/api_helpers_decorator.rb +7 -0
  14. data/app/models/spree/adjustment_decorator.rb +3 -0
  15. data/app/models/spree/inventory_unit_decorator.rb +3 -0
  16. data/app/models/spree/legacy_return_authorization.rb +108 -0
  17. data/app/models/spree/order_decorator.rb +3 -0
  18. data/app/models/spree/permission_sets/legacy_return_authorization_display.rb +9 -0
  19. data/app/models/spree/permission_sets/legacy_return_authorization_management.rb +9 -0
  20. data/app/models/spree/strong_parameters_decorator.rb +5 -0
  21. data/app/overrides/admin_legacy_return_authorizations.rb +14 -0
  22. data/app/views/spree/admin/legacy_return_authorizations/_form.html.erb +78 -0
  23. data/app/views/spree/admin/legacy_return_authorizations/edit.html.erb +32 -0
  24. data/app/views/spree/admin/legacy_return_authorizations/index.html.erb +48 -0
  25. data/app/views/spree/api/legacy_return_authorizations/index.v1.rabl +7 -0
  26. data/app/views/spree/api/legacy_return_authorizations/new.v1.rabl +3 -0
  27. data/app/views/spree/api/legacy_return_authorizations/show.v1.rabl +2 -0
  28. data/bin/rails +7 -0
  29. data/circle.yml +6 -0
  30. data/config/locales/en.yml +19 -0
  31. data/config/routes.rb +25 -0
  32. data/db/migrate/20140710044402_create_spree_legacy_return_authorizations.rb +26 -0
  33. data/lib/generators/solidus_legacy_return_authorizations/install/install_generator.rb +29 -0
  34. data/lib/solidus_legacy_return_authorizations.rb +2 -0
  35. data/lib/spree_legacy_return_authorizations/engine.rb +20 -0
  36. data/lib/spree_legacy_return_authorizations/factories.rb +13 -0
  37. data/solidus_legacy_return_authorizations.gemspec +29 -0
  38. data/spec/controllers/admin/legacy_return_authorizations_controller_spec.rb +32 -0
  39. data/spec/controllers/spree/api/legacy_return_authorizations_controller_spec.rb +157 -0
  40. data/spec/features/admin/orders/legacy_return_authorizations_spec.rb +26 -0
  41. data/spec/models/spree/legacy_return_authorization_spec.rb +214 -0
  42. data/spec/models/spree/permission_sets/legacy_return_authorization_display_spec.rb +22 -0
  43. data/spec/models/spree/permission_sets/legacy_return_authorization_management_spec.rb +20 -0
  44. data/spec/spec_helper.rb +74 -0
  45. data/spec/support/authentication_support.rb +7 -0
  46. data/spec/support/have_attributes_matcher.rb +8 -0
  47. metadata +245 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 18ac64c290153dc76aa973685a5dc58ea3190508
4
+ data.tar.gz: 539c2555b6e921869fee35ff7925b155446d3472
5
+ SHA512:
6
+ metadata.gz: b3767c15416db0beb83c325f3a50557fd3ac98c222fa9f37ae490aa9598a74bbb046b05d5405921c60638e0635b3d63230a5b20a1276bedea2d94b5ea61b478e
7
+ data.tar.gz: 79ea178bd773d20e8bdd6741dd8f6c67afb7206948f51be81a82c631c215eaccf26195d3c2d2a7bf92329c19955fe507e3dfb4f17bd0d0264665340105348eb6
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ \#*
2
+ *~
3
+ .#*
4
+ .DS_Store
5
+ .idea
6
+ .project
7
+ .sass-cache
8
+ coverage
9
+ Gemfile.lock
10
+ tmp
11
+ nbproject
12
+ pkg
13
+ *.swp
14
+ spec/dummy
15
+ .ruby-version
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "solidus", github: "solidusio/solidus", branch: "master"
4
+ gem "solidus_auth_devise", "~> 1.0"
5
+
6
+ group :development, :test do
7
+ gem "pry-rails"
8
+ end
9
+
10
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,26 @@
1
+ Copyright (c) 2014 Bonobos, Inc
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification,
5
+ are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
9
+ * Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+ * Neither the name Spree nor the names of its contributors may be used to
13
+ endorse or promote products derived from this software without specific
14
+ prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,62 @@
1
+ Solidus Legacy Return Authorizations
2
+ ====================================
3
+
4
+ This is an extension for users migrating from legacy versions of Spree (2.3.x
5
+ and prior) which had a different representation of and handling for return
6
+ authorizations.
7
+
8
+ When upgrading from a prior version of Spree to Solidus, simply include this
9
+ extension in your application's Gemfile and your old data will be preserved in
10
+ separate tables (e.g., `spree_legacy_return_authorizations`) and columns (e.g.
11
+ `spree_inventory_units.legacy_return_authorization_id`).
12
+
13
+ This extension maintains the legacy admin interfaces for viewing and closing
14
+ out (receiving/canceling) any existing legacy return authorizations. It does
15
+ not allow creating any new legacy return authorizations. New return
16
+ authorizations should be handled through the new returns system included in
17
+ Solidus.
18
+
19
+ If an order has existing legacy return authorizations then an additional admin
20
+ menu item "Legacy Return Authorizations" will appear in the admin interface for
21
+ that order (/admin/orders/XXX/edit).
22
+
23
+ Installation
24
+ ------------
25
+
26
+ Add solidus_legacy_return_authorizations to your Gemfile:
27
+
28
+ ```ruby
29
+ gem "solidus_legacy_return_authorizations"
30
+ ```
31
+
32
+ Bundle your dependencies and run the installation generator:
33
+
34
+ ```shell
35
+ bundle
36
+ bundle exec rails g solidus_legacy_return_authorizations:install
37
+ ```
38
+
39
+ Authorization
40
+ -------------
41
+
42
+ For discrete authorization, two permission sets have been added to allow for granular display in the admin.
43
+
44
+ `Spree::PermissionSets::LegacyReturnAuthorizationDisplay` and `Spree::PermissionSets::LegacyReturnAuthorizationManagement` have been added and can be assigned via [RoleConfiguration](http://docs.solidus.io/Spree/RoleConfiguration.html)
45
+
46
+
47
+ Testing
48
+ -------
49
+
50
+ First bundle your dependencies, then run `rake`. `rake` will default to building the dummy app if it does not exist, then it will run specs. The dummy app can be regenerated by using `rake test_app`.
51
+
52
+ ```shell
53
+ bundle
54
+ bundle exec rake
55
+ ```
56
+
57
+ When testing your applications integration with this extension you may use it's factories.
58
+ Simply add this require statement to your spec_helper:
59
+
60
+ ```ruby
61
+ require 'spree_legacy_return_authorizations/factories'
62
+ ```
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ require 'spree/testing_support/extension_rake'
6
+
7
+ RSpec::Core::RakeTask.new
8
+
9
+ task :default do
10
+ if Dir["spec/dummy"].empty?
11
+ Rake::Task[:test_app].invoke
12
+ Dir.chdir("../../")
13
+ end
14
+ Rake::Task[:spec].invoke
15
+ end
16
+
17
+ desc 'Generates a dummy app for testing'
18
+ task :test_app do
19
+ ENV['LIB_NAME'] = 'solidus_legacy_return_authorizations'
20
+ Rake::Task['extension:test_app'].invoke
21
+ end
@@ -0,0 +1,2 @@
1
+ // Placeholder manifest file.
2
+ // the installer will append this file to the app vendored assets here: vendor/assets/javascripts/spree/backend/all.js'
@@ -0,0 +1,4 @@
1
+ /*
2
+ Placeholder manifest file.
3
+ the installer will append this file to the app vendored assets here: 'vendor/assets/stylesheets/spree/backend/all.css'
4
+ */
@@ -0,0 +1,25 @@
1
+ module Spree
2
+ module Admin
3
+ class LegacyReturnAuthorizationsController < ResourceController
4
+ belongs_to 'spree/order', :find_by => :number
5
+
6
+ update.after :associate_inventory_units
7
+ create.after :associate_inventory_units
8
+
9
+ def fire
10
+ @legacy_return_authorization.send("#{params[:e]}!")
11
+ flash[:success] = Spree.t(:legacy_return_authorization_updated)
12
+ redirect_to :back
13
+ end
14
+
15
+ # We don't want to allow creating new legacy RMAs so remove the default methods provided by Admin::ResourceController
16
+ undef new
17
+ undef create
18
+
19
+ protected
20
+ def associate_inventory_units
21
+ (params[:return_quantity] || []).each { |variant_id, qty| @legacy_return_authorization.add_variant(variant_id.to_i, qty.to_i) }
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,74 @@
1
+ module Spree
2
+ module Api
3
+ class LegacyReturnAuthorizationsController < Spree::Api::BaseController
4
+
5
+ def destroy
6
+ @legacy_return_authorization = order.legacy_return_authorizations.accessible_by(current_ability, :destroy).find(params[:id])
7
+ @legacy_return_authorization.destroy
8
+ respond_with(@legacy_return_authorization, status: 204)
9
+ end
10
+
11
+ def index
12
+ authorize! :admin, LegacyReturnAuthorization
13
+ @legacy_return_authorizations = order.legacy_return_authorizations.accessible_by(current_ability, :read).
14
+ ransack(params[:q]).result.
15
+ page(params[:page]).per(params[:per_page])
16
+ respond_with(@legacy_return_authorizations)
17
+ end
18
+
19
+ def show
20
+ authorize! :admin, LegacyReturnAuthorization
21
+ @legacy_return_authorization = order.legacy_return_authorizations.accessible_by(current_ability, :read).find(params[:id])
22
+ respond_with(@legacy_return_authorization)
23
+ end
24
+
25
+ def update
26
+ @legacy_return_authorization = order.legacy_return_authorizations.accessible_by(current_ability, :update).find(params[:id])
27
+ if @legacy_return_authorization.update_attributes(legacy_return_authorization_params)
28
+ respond_with(@legacy_return_authorization, default_template: :show)
29
+ else
30
+ invalid_resource!(@legacy_return_authorization)
31
+ end
32
+ end
33
+
34
+ def add
35
+ @legacy_return_authorization = order.legacy_return_authorizations.accessible_by(current_ability, :update).find(params[:id])
36
+ @legacy_return_authorization.add_variant params[:variant_id].to_i, params[:quantity].to_i
37
+ if @legacy_return_authorization.valid?
38
+ respond_with @legacy_return_authorization, default_template: :show
39
+ else
40
+ invalid_resource!(@legacy_return_authorization)
41
+ end
42
+ end
43
+
44
+ def receive
45
+ @legacy_return_authorization = order.legacy_return_authorizations.accessible_by(current_ability, :update).find(params[:id])
46
+ if @legacy_return_authorization.receive
47
+ respond_with @legacy_return_authorization, default_template: :show
48
+ else
49
+ invalid_resource!(@legacy_return_authorization)
50
+ end
51
+ end
52
+
53
+ def cancel
54
+ @legacy_return_authorization = order.legacy_return_authorizations.accessible_by(current_ability, :update).find(params[:id])
55
+ if @legacy_return_authorization.cancel
56
+ respond_with @legacy_return_authorization, default_template: :show
57
+ else
58
+ invalid_resource!(@legacy_return_authorization)
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ def order
65
+ @order ||= Spree::Order.find_by!(number: order_id)
66
+ authorize! :read, @order
67
+ end
68
+
69
+ def legacy_return_authorization_params
70
+ params.require(:legacy_return_authorization).permit(permitted_legacy_return_authorization_attributes)
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,12 @@
1
+ Spree::Admin::NavigationHelper.module_eval do
2
+ def tab_with_legacy_return_authorizations(*args)
3
+ if args.first == :orders
4
+ options = args.pop if args.last.is_a?(Hash)
5
+ args << :legacy_return_authorizations
6
+ args << options
7
+ end
8
+ tab_without_legacy_return_authorizations(*args)
9
+ end
10
+
11
+ alias_method_chain :tab, :legacy_return_authorizations
12
+ end
@@ -0,0 +1,7 @@
1
+ Spree::Api::ApiHelpers.module_eval do
2
+ def legacy_return_authorization_attributes
3
+ [:id, :number, :state, :amount, :order_id, :reason, :created_at, :updated_at]
4
+ end
5
+
6
+ self.inventory_unit_attributes << :legacy_return_authorization_id
7
+ end
@@ -0,0 +1,3 @@
1
+ Spree::Adjustment.class_eval do
2
+ scope :legacy_return_authorization, -> { where(source_type: "Spree::LegacyReturnAuthorization") }
3
+ end
@@ -0,0 +1,3 @@
1
+ Spree::InventoryUnit.class_eval do
2
+ belongs_to :legacy_return_authorization, class_name: "Spree::LegacyReturnAuthorization"
3
+ end
@@ -0,0 +1,108 @@
1
+ module Spree
2
+ class LegacyReturnAuthorization < ActiveRecord::Base
3
+ belongs_to :order, class_name: 'Spree::Order'
4
+
5
+ has_many :inventory_units, dependent: :nullify
6
+ belongs_to :stock_location
7
+ before_create :generate_number
8
+ before_save :force_positive_amount
9
+
10
+ validates :order, presence: true
11
+ validates :amount, numericality: true
12
+ validate :must_have_shipped_units
13
+
14
+ state_machine initial: :authorized do
15
+ after_transition to: :received, do: :process_return
16
+
17
+ event :receive do
18
+ transition to: :received, from: :authorized, if: :allow_receive?
19
+ end
20
+ event :cancel do
21
+ transition to: :canceled, from: :authorized
22
+ end
23
+ end
24
+
25
+ def currency
26
+ order.nil? ? Spree::Config[:currency] : order.currency
27
+ end
28
+
29
+ def display_amount
30
+ Spree::Money.new(amount, { currency: currency })
31
+ end
32
+
33
+ def add_variant(variant_id, quantity)
34
+ order_units = returnable_inventory.group_by(&:variant_id)
35
+ returned_units = inventory_units.group_by(&:variant_id)
36
+ return false if order_units.empty?
37
+
38
+ count = 0
39
+
40
+ if returned_units[variant_id].nil? || returned_units[variant_id].size < quantity
41
+ count = returned_units[variant_id].nil? ? 0 : returned_units[variant_id].size
42
+
43
+ order_units[variant_id].each do |inventory_unit|
44
+ next unless inventory_unit.legacy_return_authorization.nil? && count < quantity
45
+
46
+ inventory_unit.legacy_return_authorization = self
47
+ inventory_unit.save!
48
+
49
+ count += 1
50
+ end
51
+ elsif returned_units[variant_id].size > quantity
52
+ (returned_units[variant_id].size - quantity).times do |i|
53
+ returned_units[variant_id][i].legacy_return_authorization_id = nil
54
+ returned_units[variant_id][i].save!
55
+ end
56
+ end
57
+
58
+ order.authorize_return! if inventory_units.reload.size > 0 && !order.awaiting_return?
59
+ end
60
+
61
+ def returnable_inventory
62
+ order.shipped_shipments.collect{|s| s.inventory_units.to_a}.flatten
63
+ end
64
+
65
+ # Used when Adjustment#update! wants to update the related adjustmenrt
66
+ def compute_amount(*args)
67
+ amount.abs * -1
68
+ end
69
+
70
+ private
71
+
72
+ def must_have_shipped_units
73
+ errors.add(:order, Spree.t(:has_no_shipped_units)) if order.nil? || !order.shipped_shipments.any?
74
+ end
75
+
76
+ def generate_number
77
+ self.number ||= loop do
78
+ random = "RMA#{Array.new(9){rand(9)}.join}"
79
+ break random unless self.class.exists?(number: random)
80
+ end
81
+ end
82
+
83
+ def process_return
84
+ inventory_units(include: :variant).each do |iu|
85
+ iu.return!
86
+
87
+ if iu.variant.should_track_inventory?
88
+ if stock_item = Spree::StockItem.find_by(variant_id: iu.variant_id, stock_location_id: stock_location_id)
89
+ Spree::StockMovement.create!(stock_item_id: stock_item.id, quantity: 1)
90
+ end
91
+ end
92
+ end
93
+
94
+ Adjustment.create(adjustable: order, amount: compute_amount, label: Spree.t(:legacy_rma_credit), source: self)
95
+ order.update!
96
+
97
+ order.return if inventory_units.all?(&:returned?)
98
+ end
99
+
100
+ def allow_receive?
101
+ !inventory_units.empty?
102
+ end
103
+
104
+ def force_positive_amount
105
+ self.amount = amount.abs
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,3 @@
1
+ Spree::Order.class_eval do
2
+ has_many :legacy_return_authorizations, dependent: :destroy
3
+ end
@@ -0,0 +1,9 @@
1
+ module Spree
2
+ module PermissionSets
3
+ class LegacyReturnAuthorizationDisplay < PermissionSets::Base
4
+ def activate!
5
+ can [:display, :admin], Spree::LegacyReturnAuthorization
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Spree
2
+ module PermissionSets
3
+ class LegacyReturnAuthorizationManagement < PermissionSets::Base
4
+ def activate!
5
+ can :manage, Spree::LegacyReturnAuthorization
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ Spree::Core::ControllerHelpers::StrongParameters.module_eval do
2
+ def permitted_legacy_return_authorization_attributes
3
+ [:amount, :reason, :stock_location_id]
4
+ end
5
+ end