solidus_related_products 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.hound.yml +25 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +8 -0
  6. data/.travis.yml +15 -0
  7. data/CONTRIBUTING.md +81 -0
  8. data/Gemfile +6 -0
  9. data/Guardfile +10 -0
  10. data/LICENSE.md +26 -0
  11. data/README.md +80 -0
  12. data/Rakefile +15 -0
  13. data/app/assets/javascripts/spree/backend/solidus_related_products.js +1 -0
  14. data/app/assets/javascripts/spree/frontend/solidus_related_products.js +1 -0
  15. data/app/assets/stylesheets/spree/backend/solidus_related_products.css +3 -0
  16. data/app/assets/stylesheets/spree/frontend/solidus_related_products.css +3 -0
  17. data/app/controllers/spree/admin/products_controller_decorator.rb +10 -0
  18. data/app/controllers/spree/admin/relation_types_controller.rb +6 -0
  19. data/app/controllers/spree/admin/relations_controller.rb +80 -0
  20. data/app/controllers/spree/api/relations_controller.rb +78 -0
  21. data/app/models/spree/calculator/related_product_discount.rb +50 -0
  22. data/app/models/spree/product_decorator.rb +106 -0
  23. data/app/models/spree/relation.rb +7 -0
  24. data/app/models/spree/relation_type.rb +6 -0
  25. data/app/overrides/add_product_relation_admin_sub_menu_tab.rb +6 -0
  26. data/app/overrides/add_related_product_admin_tabs.rb +6 -0
  27. data/app/views/spree/admin/products/_related_products.html.erb +3 -0
  28. data/app/views/spree/admin/products/_related_products_table.html.erb +42 -0
  29. data/app/views/spree/admin/products/related.html.erb +70 -0
  30. data/app/views/spree/admin/relation_types/_form.html.erb +19 -0
  31. data/app/views/spree/admin/relation_types/edit.html.erb +14 -0
  32. data/app/views/spree/admin/relation_types/index.html.erb +44 -0
  33. data/app/views/spree/admin/relation_types/new.html.erb +14 -0
  34. data/app/views/spree/admin/relations/create.js.erb +5 -0
  35. data/app/views/spree/admin/relations/destroy.js.erb +1 -0
  36. data/app/views/spree/api/relations/show.v1.rabl +2 -0
  37. data/bin/rails +7 -0
  38. data/config/locales/cs.yml +18 -0
  39. data/config/locales/de.yml +18 -0
  40. data/config/locales/en.yml +18 -0
  41. data/config/locales/es.yml +18 -0
  42. data/config/locales/fr.yml +18 -0
  43. data/config/locales/it.yml +18 -0
  44. data/config/locales/nl.yml +18 -0
  45. data/config/locales/pl.yml +18 -0
  46. data/config/locales/pt-BR.yml +18 -0
  47. data/config/locales/ru.yml +18 -0
  48. data/config/locales/sv.yml +18 -0
  49. data/config/routes.rb +24 -0
  50. data/db/migrate/20100308090631_create_relation_types.rb +14 -0
  51. data/db/migrate/20100308092101_create_relations.rb +14 -0
  52. data/db/migrate/20100324123835_add_discount_to_relation.rb +9 -0
  53. data/db/migrate/20111129044813_prefixing_tables_with_spree.rb +6 -0
  54. data/db/migrate/20120208144454_update_relation_types.rb +9 -0
  55. data/db/migrate/20120623014337_update_relations.rb +11 -0
  56. data/db/migrate/20130727004612_add_position_to_spree_relations.rb +5 -0
  57. data/lib/generators/solidus_related_products/install/install_generator.rb +20 -0
  58. data/lib/solidus_related_products.rb +7 -0
  59. data/lib/solidus_related_products/engine.rb +24 -0
  60. data/lib/solidus_related_products/version.rb +18 -0
  61. data/solidus_related_products.gemspec +45 -0
  62. data/spec/controllers/spree/admin/products_controller_decorator_spec.rb +20 -0
  63. data/spec/controllers/spree/admin/relations_controller_spec.rb +96 -0
  64. data/spec/controllers/spree/api/relations_controller_spec.rb +98 -0
  65. data/spec/factories/relation_factory.rb +7 -0
  66. data/spec/factories/relation_type_factory.rb +6 -0
  67. data/spec/features/spree/admin/product_relation_spec.rb +86 -0
  68. data/spec/features/spree/admin/relation_types_spec.rb +97 -0
  69. data/spec/models/spree/calculator/related_product_discount_spec.rb +48 -0
  70. data/spec/models/spree/product_spec.rb +129 -0
  71. data/spec/models/spree/relation_spec.rb +13 -0
  72. data/spec/models/spree/relation_type_spec.rb +18 -0
  73. data/spec/spec_helper.rb +48 -0
  74. data/spec/support/capybara.rb +20 -0
  75. data/spec/support/database_cleaner.rb +23 -0
  76. data/spec/support/factory_girl.rb +7 -0
  77. data/spec/support/spree.rb +18 -0
  78. metadata +388 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 796ec99b0714a1e62195cac718d7ee685e444885
4
+ data.tar.gz: 383f4d8974811a381e1ab46ca51078bdd4bb00d2
5
+ SHA512:
6
+ metadata.gz: df78c358ae876c2d31319614c7122020379ccdd6b7c1720646874b69b15c2164afe2fd03c22671093f6af4d236e0725b98cb0bbbfcf9932c71749741d2e0df75
7
+ data.tar.gz: 335f7498dbe1557d39fed0f93dadb058fbfce3bec0e66ef213b8d2953b479e3bf28d7d28c90a769bc66a60bd8111f317bffd58301a96951948b4b3cb8e77866c
@@ -0,0 +1,12 @@
1
+ *.swp
2
+ .DS_Store
3
+ .rvmrc
4
+ Gemfile.lock
5
+ pkg
6
+ spec/dummy
7
+ *~
8
+ tmp
9
+ .localeapp
10
+ coverage
11
+ .ruby-version
12
+ .ruby-gemset
@@ -0,0 +1,25 @@
1
+ ---
2
+ # Too picky.
3
+ LineLength:
4
+ Enabled: false
5
+
6
+ # This should truly be on for well documented gems.
7
+ Documentation:
8
+ Enabled: false
9
+
10
+ # Neatly aligned code is too swell.
11
+ SpaceBeforeFirstArg:
12
+ Enabled: false
13
+
14
+ # Don't mess with RSpec DSL.
15
+ Blocks:
16
+ Exclude:
17
+ - 'spec/**/*'
18
+
19
+ # It say we should use fail over raise.
20
+ SignalException:
21
+ Enabled: false
22
+
23
+ # Avoid contradictory style rules by enforce single quotes.
24
+ StringLiterals:
25
+ EnforcedStyle: single_quotes
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ -r spec_helper
3
+ -f documentation
@@ -0,0 +1,8 @@
1
+ ---
2
+ inherit_from: .hound.yml
3
+
4
+ AllCops:
5
+ Exclude:
6
+ - spec/dummy/**/*
7
+ - bin/*
8
+ - Guardfile
@@ -0,0 +1,15 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1
4
+ - 2.2
5
+ sudo: false
6
+ cache: bundler
7
+ env:
8
+ matrix:
9
+ - SOLIDUS_BRANCH=master
10
+ - SOLIDUS_BRANCH=v1.2
11
+ - SOLIDUS_BRANCH=v1.1
12
+ before_script:
13
+ - bundle exec rake test_app
14
+ script:
15
+ - bundle exec rspec spec
@@ -0,0 +1,81 @@
1
+ # Contributing
2
+
3
+ Spree Related Products is an open source project and we encourage contributions. Please see the [contributors guidelines](http://spreecommerce.com/documentation/contributing_to_spree.html) for more information before contributing.
4
+
5
+ In the spirit of [free software][1], **everyone** is encouraged to help improve this project.
6
+
7
+ Here are some ways *you* can contribute:
8
+
9
+ * by using prerelease versions
10
+ * by reporting [bugs][2]
11
+ * by suggesting new features
12
+ * by writing [translations][3]
13
+ * by writing or editing documentation
14
+ * by writing specifications
15
+ * by writing code (*no patch is too small*: fix typos, add comments, clean up inconsistent whitespace)
16
+ * by refactoring code
17
+ * by resolving [issues][2]
18
+ * by reviewing patches
19
+
20
+ ---
21
+
22
+ ## Filing an issue
23
+
24
+ When filing an issue on this extension, please first do these things:
25
+
26
+ * Verify you can reproduce this issue in a brand new application.
27
+ * Run through the steps to reproduce the issue again.
28
+
29
+ In the issue itself please provide:
30
+
31
+ * A comprehensive list of steps to reproduce the issue.
32
+ * What you're *expecting* to happen compared with what's *actually* happening.
33
+ * The version of Spree *and* the version of Rails.
34
+ * A list of all extensions.
35
+ * Any relevant stack traces ("Full trace" preferred)
36
+ * Your `Gemfile`
37
+
38
+ In 99% of cases, this information is enough to determine the cause and solution to the problem that is being described.
39
+
40
+ ---
41
+
42
+ ## Pull requests
43
+
44
+ We gladly accept pull requests to fix bugs and, in some circumstances, add new features to this extension.
45
+
46
+ Here's a quick guide:
47
+
48
+ 1. Fork the repo.
49
+
50
+ 2. Run the tests. We only take pull requests with passing tests, and it's great to know that you have a clean slate.
51
+
52
+ 3. Create new branch then make changes and add tests for your changes. Only refactoring and documentation changes require no new tests. If you are adding functionality or fixing a bug, we need tests!
53
+
54
+ 4. Push to your fork and submit a pull request. If the changes will apply cleanly to the latest stable branches and master branch, you will only need to submit one pull request.
55
+
56
+ At this point you're waiting on us. We may suggest some changes or improvements or alternatives.
57
+
58
+ Some things that will increase the chance that your pull request is accepted, taken straight from the Ruby on Rails guide:
59
+
60
+ * Use Rails idioms and helpers.
61
+ * Include tests that fail without your code, and pass with it.
62
+ * Update the documentation, the surrounding one, examples elsewhere, guides, whatever is affected by your contribution.
63
+
64
+ ---
65
+
66
+ ## TL;DR
67
+
68
+ * Fork the repo
69
+ * Clone your repo
70
+ * Run `bundle install`
71
+ * Run `bundle exec rake test_app` to create the test application in `spec/dummy`
72
+ * Make your changes
73
+ * Ensure specs pass by running `bundle exec rspec spec`
74
+ * Ensure all syntax ok by running `rubocop .`
75
+ * Submit your pull request
76
+
77
+ And in case we didn't emphasize it enough: **we love tests!**
78
+
79
+ [1]: http://www.fsf.org/licensing/essays/free-sw.html
80
+ [2]: https://github.com/spree-contrib/spree_related_products/issues
81
+ [3]: https://github.com/spree-contrib/spree_related_products/tree/master/config/locales
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ branch = ENV.fetch('SOLIDUS_BRANCH', 'master')
4
+ gem 'solidus', github: 'solidusio/solidus', branch: branch
5
+
6
+ gemspec
@@ -0,0 +1,10 @@
1
+ guard 'rspec', cmd: 'bundle exec rspec' do
2
+ watch('spec/spec_helper.rb') { 'spec' }
3
+ watch('config/routes.rb') { 'spec/controllers' }
4
+ watch(%r{^spec/(.+)_spec\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
5
+ watch(%r{^app/(.+)_decorator\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
6
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
7
+ watch(%r{^app/(.*)(\.erb)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
8
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
9
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb" }
10
+ end
@@ -0,0 +1,26 @@
1
+ Copyright (c) 2010-2015 Brian Quinn and contributors.
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.
@@ -0,0 +1,80 @@
1
+ # Related Products
2
+
3
+ [![Build Status](https://travis-ci.org/solidusio-contrib/solidus_related_products.svg?branch=master)](https://travis-ci.org/solidusio-contrib/solidus_related_products)
4
+ [![Gem](https://img.shields.io/gem/v/solidus_related_products.svg)](https://rubygems.org/gems/solidus_related_products)
5
+ [![License](http://img.shields.io/badge/license-BSD-yellowgreen.svg)](LICENSE.md)
6
+
7
+ This extension provides a generic way for you to define different types of relationships between your products, by defining a RelationType for each type of relationship you'd like to maintain.
8
+
9
+ You can manage RelationTypes via the admin configuration menu, and you can maintain product relationships via __Related Products__ tab on the edit product UI.
10
+
11
+ ## Installation
12
+
13
+ Add to `Gemfile`:
14
+ ```ruby
15
+ gem 'spree_related_products'
16
+ ```
17
+
18
+ Run:
19
+ ```sh
20
+ $ bundle install
21
+ $ bundle exec rails g solidus_related_products:install
22
+ ```
23
+
24
+ ## Possible uses
25
+
26
+ * Accessories
27
+ * Cross Sells
28
+ * Up Sells
29
+ * Compatible Products
30
+ * Replacement Products
31
+ * Warranty & Support Products
32
+
33
+ ## Relation Types
34
+
35
+ When you create a RelationType you can access that set of related products by referencing the relation_type name, see below for an example:
36
+ ```ruby
37
+ rt = Spree::RelationType.create(name: 'Accessories', applies_to: 'Spree::Product')
38
+ => #<Spree::RelationType id: 4, name: "Accessories" ...>
39
+ product = Spree::Product.last
40
+ => #<Spree::Product id: 1060500592 ...>
41
+ product.accessories
42
+ => []
43
+ ```
44
+
45
+ Since respond_to? will not work in this case, you can test whether a relation_type method exists with has_related_products?(method):
46
+
47
+ ```ruby
48
+ product.has_related_products?('accessories')
49
+ # => true
50
+
51
+ if product.has_related_products?('accessories')
52
+ # Display an accessories box..
53
+ end
54
+ ```
55
+
56
+ You can access all related products regardless of RelationType by:
57
+ ```ruby
58
+ product.relations
59
+ => []
60
+ ```
61
+
62
+ **Discounts**
63
+ You can optionally specify a discount amount to be applied if a customer purchases both products.
64
+
65
+ Note: In order for the coupon to be automatically applied, you must create a promotion leaving the __code__ value empty, and adding an Action of type : __RelatedProductDiscount__ (blank codes are required for coupons to be automatically applied).
66
+
67
+ ## Contributing
68
+
69
+ See corresponding [guidelines][4]
70
+
71
+ ---
72
+
73
+ Copyright (c) 2010-2015 [Brian Quinn][5] and [contributors][6], released under the [New BSD License][3]
74
+
75
+ [1]: http://www.fsf.org/licensing/essays/free-sw.html
76
+ [2]: https://github.com/spree-contrib/spree_related_products/issues
77
+ [3]: https://github.com/spree-contrib/spree_related_products/blob/master/LICENSE.md
78
+ [4]: https://github.com/spree-contrib/spree_related_products/blob/master/CONTRIBUTING.md
79
+ [5]: https://github.com/BDQ
80
+ [6]: https://github.com/spree-contrib/spree_related_products/graphs/contributors
@@ -0,0 +1,15 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ require 'spree/testing_support/common_rake'
6
+
7
+ RSpec::Core::RakeTask.new
8
+
9
+ task default: :spec
10
+
11
+ desc 'Generates a dummy app for testing'
12
+ task :test_app do
13
+ ENV['LIB_NAME'] = 'solidus_related_products'
14
+ Rake::Task['common:test_app'].invoke
15
+ end
@@ -0,0 +1 @@
1
+ //= require spree/backend
@@ -0,0 +1 @@
1
+ //= require spree/frontend
@@ -0,0 +1,3 @@
1
+ /*
2
+ *= require spree/backend
3
+ */
@@ -0,0 +1,3 @@
1
+ /*
2
+ *= require spree/frontend
3
+ */
@@ -0,0 +1,10 @@
1
+ module Spree
2
+ module Admin
3
+ ProductsController.class_eval do
4
+ def related
5
+ load_resource
6
+ @relation_types = Spree::Product.relation_types
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,6 @@
1
+ module Spree
2
+ module Admin
3
+ class RelationTypesController < ResourceController
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,80 @@
1
+ module Spree
2
+ module Admin
3
+ class RelationsController < BaseController
4
+ before_action :load_data, only: [:create, :destroy]
5
+
6
+ respond_to :js, :html
7
+
8
+ def create
9
+ @relation = Relation.new(relation_params)
10
+ @relation.relatable = @product
11
+ @relation.related_to = Spree::Variant.find(relation_params[:related_to_id]).product
12
+ @relation.save
13
+
14
+ respond_with(@relation)
15
+ end
16
+
17
+ def update
18
+ @relation = Relation.find(params[:id])
19
+ @relation.update_attribute :discount_amount, relation_params[:discount_amount] || 0
20
+
21
+ redirect_to(related_admin_product_url(@relation.relatable))
22
+ end
23
+
24
+ def update_positions
25
+ params[:positions].each do |id, index|
26
+ model_class.where(id: id).update_all(position: index)
27
+ end
28
+
29
+ respond_to do |format|
30
+ format.js { render text: 'Ok' }
31
+ end
32
+ end
33
+
34
+ def destroy
35
+ @relation = Relation.find(params[:id])
36
+ if @relation.destroy
37
+ flash[:success] = flash_message_for(@relation, :successfully_removed)
38
+
39
+ respond_with(@relation) do |format|
40
+ format.html { redirect_to location_after_destroy }
41
+ format.js { render :partial => "spree/admin/shared/destroy" }
42
+ end
43
+
44
+ else
45
+
46
+ respond_with(@relation) do |format|
47
+ format.html { redirect_to location_after_destroy }
48
+ end
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def relation_params
55
+ params.require(:relation).permit(*permitted_attributes)
56
+ end
57
+
58
+ def permitted_attributes
59
+ [
60
+ :related_to,
61
+ :relation_type,
62
+ :relatable,
63
+ :related_to_id,
64
+ :discount_amount,
65
+ :relation_type_id,
66
+ :related_to_type,
67
+ :position
68
+ ]
69
+ end
70
+
71
+ def load_data
72
+ @product = Spree::Product.friendly.find(params[:product_id])
73
+ end
74
+
75
+ def model_class
76
+ Spree::Relation
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,78 @@
1
+ module Spree
2
+ module Api
3
+ class RelationsController < Spree::Api::BaseController
4
+ before_action :load_data, only: [:create, :destroy]
5
+ before_action :find_relation, only: [:update, :destroy]
6
+
7
+ def create
8
+ authorize! :create, Relation
9
+ @relation = @product.relations.new(relation_params)
10
+ @relation.relatable = @product
11
+ @relation.related_to = Spree::Variant.find(relation_params[:related_to_id]).product
12
+ if @relation.save
13
+ respond_with(@relation, status: 201, default_template: :show)
14
+ else
15
+ invalid_resource!(@relation)
16
+ end
17
+ end
18
+
19
+ def update
20
+ authorize! :update, Relation
21
+ if @relation.update_attributes(relation_params)
22
+ respond_with(@relation, status: 200, default_template: :show)
23
+ else
24
+ invalid_resource!(@relation)
25
+ end
26
+ end
27
+
28
+ def update_positions
29
+ authorize! :update, Relation
30
+ params[:positions].each do |id, index|
31
+ model_class.where(id: id).update_all(position: index)
32
+ end
33
+
34
+ respond_to do |format|
35
+ format.json { render nothing: true, status: 200 }
36
+ format.js { render text: 'Ok' }
37
+ end
38
+ end
39
+
40
+ def destroy
41
+ authorize! :destroy, Relation
42
+ @relation.destroy
43
+ respond_with(@relation, status: 204)
44
+ end
45
+
46
+ private
47
+
48
+ def relation_params
49
+ params.require(:relation).permit(*permitted_attributes)
50
+ end
51
+
52
+ def permitted_attributes
53
+ [
54
+ :related_to,
55
+ :relation_type,
56
+ :relatable,
57
+ :related_to_id,
58
+ :discount_amount,
59
+ :relation_type_id,
60
+ :related_to_type,
61
+ :position
62
+ ]
63
+ end
64
+
65
+ def load_data
66
+ @product = Spree::Product.friendly.find(params[:product_id])
67
+ end
68
+
69
+ def find_relation
70
+ @relation = Relation.find(params[:id])
71
+ end
72
+
73
+ def model_class
74
+ Spree::Relation
75
+ end
76
+ end
77
+ end
78
+ end