solidus_multi_domain 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +33 -0
  3. data/.rspec +4 -0
  4. data/.ruby-version +1 -0
  5. data/Gemfile +9 -0
  6. data/README.md +72 -0
  7. data/Rakefile +21 -0
  8. data/app/controllers/concerns/spree_multi_domain/create_line_item_support.rb +16 -0
  9. data/app/controllers/concerns/spree_multi_domain/show_product_support.rb +17 -0
  10. data/app/controllers/spree/admin/products_controller_decorator.rb +12 -0
  11. data/app/controllers/spree/admin/stores_controller.rb +24 -0
  12. data/app/controllers/spree/api/line_items_controller_decorator.rb +1 -0
  13. data/app/controllers/spree/api/orders_controller_decorator.rb +21 -0
  14. data/app/controllers/spree/api/products_controller_decorator.rb +1 -0
  15. data/app/controllers/spree/api/shipments_controller_decorator.rb +17 -0
  16. data/app/controllers/spree/home_controller_decorator.rb +7 -0
  17. data/app/controllers/spree/products_controller_decorator.rb +1 -0
  18. data/app/controllers/spree/taxons_controller_decorator.rb +10 -0
  19. data/app/helpers/spree/products_helper_decorator.rb +11 -0
  20. data/app/mailers/spree/carton_mailer_decorator.rb +13 -0
  21. data/app/mailers/spree/order_mailer.rb +35 -0
  22. data/app/models/spree/order_decorator.rb +8 -0
  23. data/app/models/spree/payment_method_decorator.rb +13 -0
  24. data/app/models/spree/product_decorator.rb +4 -0
  25. data/app/models/spree/promotion/rules/store.rb +30 -0
  26. data/app/models/spree/shipping_method_decorator.rb +18 -0
  27. data/app/models/spree/store_decorator.rb +25 -0
  28. data/app/models/spree/store_payment_method.rb +6 -0
  29. data/app/models/spree/store_shipping_method.rb +6 -0
  30. data/app/models/spree/taxon_decorator.rb +5 -0
  31. data/app/models/spree/taxonomy_decorator.rb +3 -0
  32. data/app/models/spree/tracker_decorator.rb +7 -0
  33. data/app/models/spree_multi_domain/line_item_decorator.rb +20 -0
  34. data/app/overrides/decorate_admin_configurations_index.rb +5 -0
  35. data/app/overrides/decorate_admin_products_form.rb +6 -0
  36. data/app/overrides/decorate_admin_products_index.rb +20 -0
  37. data/app/overrides/decorate_admin_trackers_form.rb +6 -0
  38. data/app/overrides/decorate_admin_trackers_index.rb +13 -0
  39. data/app/views/spree/admin/products/_index_headers.html.erb +1 -0
  40. data/app/views/spree/admin/products/_index_rows.html.erb +1 -0
  41. data/app/views/spree/admin/products/_index_search_fields.html.erb +4 -0
  42. data/app/views/spree/admin/products/_stores.html.erb +8 -0
  43. data/app/views/spree/admin/promotions/rules/_store.html.erb +8 -0
  44. data/app/views/spree/admin/stores/_form.html.erb +90 -0
  45. data/app/views/spree/admin/stores/edit.html.erb +29 -0
  46. data/app/views/spree/admin/stores/index.html.erb +43 -0
  47. data/app/views/spree/admin/stores/new.html.erb +29 -0
  48. data/app/views/spree/admin/taxonomies/_form.html.erb +12 -0
  49. data/app/views/spree/admin/trackers/_index_rows.html.erb +1 -0
  50. data/app/views/spree/admin/trackers/_store.html.erb +6 -0
  51. data/app/views/spree/shared/_google_analytics.html.erb +39 -0
  52. data/bin/rails +7 -0
  53. data/circle.yml +6 -0
  54. data/config/locales/en.yml +26 -0
  55. data/config/locales/fr.yml +9 -0
  56. data/config/locales/pl.yml +10 -0
  57. data/config/locales/ru.yml +9 -0
  58. data/config/routes.rb +5 -0
  59. data/db/migrate/20091202123245_add_order_store.rb +17 -0
  60. data/db/migrate/20100114020535_add_store_to_tracker.rb +25 -0
  61. data/db/migrate/20100227180338_create_products_stores.rb +13 -0
  62. data/db/migrate/20100616204303_store_id_for_taxonomies.rb +19 -0
  63. data/db/migrate/20110601125650_remove_datetime_columns_from_products_stores.rb +13 -0
  64. data/db/migrate/20110601145424_add_indexes_to_products_stores.rb +11 -0
  65. data/db/migrate/20120223183401_namespace.rb +9 -0
  66. data/db/migrate/20121210224018_add_store_payment_methods.rb +10 -0
  67. data/db/migrate/20130308084714_add_logo_to_stores.rb +13 -0
  68. data/db/migrate/20130325231147_add_store_shipping_methods.rb +14 -0
  69. data/db/migrate/20130412212659_add_spree_promotion_rules_stores.rb +8 -0
  70. data/db/migrate/20150304200122_add_indexes.rb +6 -0
  71. data/lib/assets/javascripts/spree/backend/solidus_multi_domain.js +1 -0
  72. data/lib/assets/javascripts/spree/backend/store_picker.js +34 -0
  73. data/lib/assets/javascripts/spree/frontend/solidus_multi_domain.js +0 -0
  74. data/lib/assets/stylesheets/spree/frontend/solidus_multi_domain.css +5 -0
  75. data/lib/generators/spree_multi_domain/install/install_generator.rb +24 -0
  76. data/lib/solidus_multi_domain.rb +3 -0
  77. data/lib/spree/controller_helpers/order_decorator.rb +11 -0
  78. data/lib/spree/search/multi_domain.rb +19 -0
  79. data/lib/spree_multi_domain/engine.rb +65 -0
  80. data/lib/spree_multi_domain/multi_domain_helpers.rb +31 -0
  81. data/solidus_multi_domain.gemspec +31 -0
  82. data/spec/controllers/spree/admin/products_controller_spec.rb +39 -0
  83. data/spec/controllers/spree/admin/stores_controller_spec.rb +12 -0
  84. data/spec/controllers/spree/api/line_items_controller_spec.rb +35 -0
  85. data/spec/controllers/spree/api/orders_controller_spec.rb +44 -0
  86. data/spec/controllers/spree/api/products_controller_spec.rb +52 -0
  87. data/spec/controllers/spree/api/shipments_controller_spec.rb +63 -0
  88. data/spec/controllers/spree/products_controller_spec.rb +49 -0
  89. data/spec/helpers/products_helper_decorator_spec.rb +22 -0
  90. data/spec/mailers/carton_mailer_spec.rb +41 -0
  91. data/spec/models/spree/line_item_spec.rb +39 -0
  92. data/spec/models/spree/order_spec.rb +18 -0
  93. data/spec/models/spree/payment_method_spec.rb +33 -0
  94. data/spec/models/spree/product_spec.rb +18 -0
  95. data/spec/models/spree/shipping_method_decorator_spec.rb +27 -0
  96. data/spec/models/spree/store_spec.rb +42 -0
  97. data/spec/models/spree/taxon_decorator_spec.rb +30 -0
  98. data/spec/models/spree/tracker_spec.rb +19 -0
  99. data/spec/requests/global_controller_helpers_spec.rb +65 -0
  100. data/spec/requests/template_renderer_spec.rb +25 -0
  101. data/spec/spec_helper.rb +33 -0
  102. data/spec/support/factory_overrides.rb +10 -0
  103. metadata +278 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 52d337168f77ee0a5c1645598299ae808ab415e4
4
+ data.tar.gz: 2bc617558995dfb85db2a816feb05e8be58efab9
5
+ SHA512:
6
+ metadata.gz: 2d4b32d871c50b2e5a8b8abba49bd16103904da4037a7789d6b849720231712ecf151954d192aef5e3660223c67ba17be04912da400ede556457cbff5068b913
7
+ data.tar.gz: f491bf9f85566ac2f0b2be660e02cba7ba3654b78b0f3c768591a1d108a3886ed33ff26f4523b87cb8bfeb21dff72b124902428bc6931ed35c9ca6e81644f413
data/.gitignore ADDED
@@ -0,0 +1,33 @@
1
+ \#*
2
+ **/*.db
3
+ *~
4
+ .#*
5
+ .DS_Store
6
+ .dotest
7
+ .idea
8
+ .loadpath
9
+ .project
10
+ *.swp
11
+ spec/dummy
12
+ config/*-public.asc
13
+ config/database.yml
14
+ config/mongrel_cluster.yml
15
+ db/*.sql
16
+ db/*.sqlite3*
17
+ db/schema.rb
18
+ doc/**/*
19
+ log/*.log
20
+ public/assets
21
+ public/images
22
+ public/javascripts
23
+ public/stylesheets
24
+ tmp
25
+ vendor/rails
26
+ vendor/extensions/google_base
27
+ public/google_base.xml
28
+ public/template_google_base.xml
29
+ coverage/*
30
+ .bundle
31
+ Gemfile.lock
32
+ .ruby-version
33
+ .ruby-gemset
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --color
2
+ --format
3
+ progress
4
+ --backtrace
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.1.6
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "solidus", git: "git@github.com:solidusio/solidus.git", branch: "master"
4
+
5
+ group :development, :test do
6
+ gem "pry-rails"
7
+ end
8
+
9
+ gemspec
data/README.md ADDED
@@ -0,0 +1,72 @@
1
+ Multi Domain Store
2
+ ==================
3
+
4
+ This extension allows a single Solidus instance to have several customer facing
5
+ stores, with a single shared backend administration system (i.e. multi-store,
6
+ single-vendor).
7
+
8
+ Current features:
9
+ ------------------
10
+
11
+ 1. **Store** model which has the following attributes:
12
+
13
+ 1.1 name - The display name for the store.
14
+
15
+ 1.2 domains - a line separated list of fully qualified domain names used to
16
+ associate a customers session with a particular store (you can use
17
+ localhost and/or IP addresses too).
18
+
19
+ 1.3 code - which is a abbreviated version of the store's name (used as the
20
+ layout directory name, and also helpful for separating partials by store).
21
+
22
+ 1.4 default - one store should be marked a default as a fallback in case
23
+ the URL being used to access the site cannot be matched against any of the
24
+ configured stores.
25
+
26
+ 2. Stores and domains can be maintained via the configuration section of the
27
+ Admin interface
28
+
29
+ 2. Each store can have its own layout(s) - these layouts should be located in
30
+ your site's theme extension in the
31
+ app/views/spree/layouts/_store#code_/directory. So, if you have a store
32
+ with a code of "alpha" you should store its default layout in
33
+ app/views/spree/layouts/alpha/spree_application.html.erb
34
+
35
+ 3. Each product can be assigned to one or more stores.
36
+
37
+ 4. All orders are associated with the store / domain that they were placed on.
38
+
39
+ 5. Google analytics trackers can be associated with a store.
40
+
41
+ Install Instructions
42
+ --------------------
43
+
44
+ Add to your Gemfile:
45
+
46
+ ```ruby
47
+ gem "solidus_multi_domain"
48
+ ```
49
+
50
+ Then run from the command line:
51
+
52
+ ```shell
53
+ bundle install
54
+ rails g spree_multi_domain:install
55
+ ```
56
+
57
+ You should see 'Stores & Domains' in Configuration tab of Spree Admin.
58
+
59
+ Features To-do
60
+ --------------
61
+
62
+ 1. Taxonomies - associate stores with taxonomies.
63
+
64
+ Testing
65
+ -------
66
+
67
+ Then just run the following to automatically build a dummy app if necessary and
68
+ run the tests:
69
+
70
+ ```shell
71
+ bundle exec rake
72
+ ```
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/common_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_multi_domain'
20
+ Rake::Task['common:test_app'].invoke
21
+ end
@@ -0,0 +1,16 @@
1
+ module SpreeMultiDomain::CreateLineItemSupport
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ prepend(InstanceMethods)
6
+ rescue_from SpreeMultiDomain::LineItemDecorator::ProductDoesNotBelongToStoreError, with: :product_does_not_belong_to_store
7
+ end
8
+
9
+ module InstanceMethods
10
+ private
11
+
12
+ def product_does_not_belong_to_store
13
+ render json: { message: Spree.t('errors.products_from_different_stores_may_not_be_added_to_this_order') }, status: 422
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ module SpreeMultiDomain::ShowProductSupport
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ prepend(InstanceMethods)
6
+ before_filter :can_show_product, :only => :show
7
+ end
8
+
9
+ module InstanceMethods
10
+ def can_show_product
11
+ @product ||= Spree::Product.friendly.find(params[:id])
12
+ if @product.stores.empty? || !@product.stores.include?(current_store)
13
+ raise ActiveRecord::RecordNotFound
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ Spree::Admin::ProductsController.class_eval do
2
+ update.before :set_stores
3
+
4
+ private
5
+ def set_stores
6
+ # Remove all store associations if store data is being passed and no stores are selected
7
+ if params[:update_store_ids] && !params[:product].key?(:store_ids)
8
+ @product.stores.clear
9
+ end
10
+ end
11
+
12
+ end
@@ -0,0 +1,24 @@
1
+ class Spree::Admin::StoresController < Spree::Admin::ResourceController
2
+
3
+ before_filter :load_payment_methods
4
+ before_filter :load_shipping_methods
5
+
6
+ def index
7
+ @stores = @stores.ransack({ name_or_domains_or_code_cont: params[:q] }).result if params[:q]
8
+ @stores = @stores.where(id: params[:ids].split(',')) if params[:ids]
9
+
10
+ respond_with(@stores) do |format|
11
+ format.html
12
+ format.json
13
+ end
14
+ end
15
+
16
+ private
17
+ def load_payment_methods
18
+ @payment_methods = Spree::PaymentMethod.all
19
+ end
20
+
21
+ def load_shipping_methods
22
+ @shipping_methods = Spree::ShippingMethod.all
23
+ end
24
+ end
@@ -0,0 +1 @@
1
+ Spree::Api::LineItemsController.include SpreeMultiDomain::CreateLineItemSupport
@@ -0,0 +1,21 @@
1
+ module SpreeMultiStore
2
+ module Api
3
+ module OrdersControllerDecorator
4
+ def self.included(base)
5
+ base.alias_method_chain :mine, :store_scope
6
+ base.alias_method_chain :find_current_api_user_orders, :store_scope
7
+ end
8
+
9
+ def mine_with_store_scope
10
+ mine_without_store_scope
11
+ @orders = @orders.where(store: current_store) if @orders
12
+ end
13
+
14
+ def find_current_api_user_orders_with_store_scope
15
+ find_current_api_user_orders_without_store_scope.where(store: current_store)
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ Spree::Api::OrdersController.include SpreeMultiStore::Api::OrdersControllerDecorator
@@ -0,0 +1 @@
1
+ Spree::Api::ProductsController.include(SpreeMultiDomain::ShowProductSupport)
@@ -0,0 +1,17 @@
1
+ module SpreeMultiStore
2
+ module Api
3
+ module ShipmentsControllerDecorator
4
+ def self.included(base)
5
+ base.alias_method_chain :mine, :store_scope
6
+ end
7
+
8
+ def mine_with_store_scope
9
+ mine_without_store_scope
10
+ @shipments = @shipments.where(spree_orders: { store_id: current_store.id }) if @shipments
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ Spree::Api::ShipmentsController.include SpreeMultiStore::Api::ShipmentsControllerDecorator
17
+ Spree::Api::ShipmentsController.include SpreeMultiDomain::CreateLineItemSupport
@@ -0,0 +1,7 @@
1
+ Spree::HomeController.class_eval do
2
+ def index
3
+ @searcher = build_searcher(params)
4
+ @products = @searcher.retrieve_products
5
+ @taxonomies = get_taxonomies
6
+ end
7
+ end
@@ -0,0 +1 @@
1
+ Spree::ProductsController.include(SpreeMultiDomain::ShowProductSupport)
@@ -0,0 +1,10 @@
1
+ Spree::TaxonsController.class_eval do
2
+ def show
3
+ @taxon = Spree::Taxon.find_by_store_id_and_permalink!(current_store.id, params[:id])
4
+ return unless @taxon
5
+
6
+ @searcher = build_searcher(params.merge(:taxon => @taxon.id))
7
+ @products = @searcher.retrieve_products
8
+ @taxonomies = get_taxonomies
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ module Spree
2
+ module Api
3
+ ProductsHelper.class_eval do
4
+ def get_taxonomies
5
+ @taxonomies ||= current_store.present? ? Spree::Taxonomy.where(["store_id = ?", current_store.id]) : Spree::Taxonomy
6
+ @taxonomies = @taxonomies.includes(:root => :children)
7
+ @taxonomies
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ Spree::CartonMailer.class_eval do
2
+ def from_address_with_multidomain
3
+ order = @carton.orders.first
4
+
5
+ if order.store
6
+ order.store.mail_from_address
7
+ else
8
+ from_address_without_multidomain
9
+ end
10
+ end
11
+
12
+ alias_method_chain :from_address, :multidomain
13
+ end
@@ -0,0 +1,35 @@
1
+ module Spree
2
+ class OrderMailer < BaseMailer
3
+ def confirm_email(order, resend = false)
4
+ find_order(order)
5
+ subject = (resend ? "[#{Spree.t(:resend).upcase}] " : '')
6
+ subject += "#{Spree::Store.default.name} #{Spree.t('order_mailer.confirm_email.subject')} ##{@order.number}"
7
+ mail_params = {:to => @order.email, :subject => subject}
8
+ if @order.store.present? && @order.store.mail_from_address.present?
9
+ mail_params[:from] = @order.store.mail_from_address
10
+ else
11
+ mail_params[:from] = Spree::Store.default.mail_from_address
12
+ end
13
+ mail(mail_params)
14
+ end
15
+
16
+ def cancel_email(order, resend = false)
17
+ find_order(order)
18
+ subject = (resend ? "[#{Spree.t(:resend).upcase}] " : '')
19
+ subject += "#{Spree::Store.default.name} #{Spree.t('order_mailer.cancel_email.subject')} ##{@order.number}"
20
+ mail_params = {:to => @order.email, :subject => subject}
21
+ if @order.store.present? && @order.store.mail_from_address.present?
22
+ mail_params[:from] = @order.store.mail_from_address
23
+ else
24
+ mail_params[:from] = Spree::Store.default.mail_from_address
25
+ end
26
+ mail(mail_params)
27
+ end
28
+
29
+ private
30
+
31
+ def find_order(order)
32
+ @order = order.is_a?(Spree::Order) ? order : Spree::Order.find(order)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,8 @@
1
+ Spree::Order.class_eval do
2
+ belongs_to :store
3
+ scope :by_store, lambda { |store| where(:store_id => store.id) }
4
+
5
+ def available_payment_methods
6
+ @available_payment_methods ||= Spree::PaymentMethod.available(:front_end, store)
7
+ end
8
+ end
@@ -0,0 +1,13 @@
1
+ Spree::PaymentMethod.class_eval do
2
+ has_many :store_payment_methods
3
+ has_many :stores, :through => :store_payment_methods
4
+
5
+ def self.available(display_on = 'both', store = nil)
6
+ result = all.select do |p|
7
+ p.active &&
8
+ (p.environment == Rails.env || p.environment.blank?) &&
9
+ (store.nil? || store.payment_methods.empty? || store.payment_methods.include?(p)) &&
10
+ (p.display_on == display_on.to_s || p.display_on.blank?)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,4 @@
1
+ Spree::Product.class_eval do
2
+ has_and_belongs_to_many :stores, :join_table => 'spree_products_stores'
3
+ scope :by_store, lambda { |store| joins(:stores).where("spree_products_stores.store_id = ?", store) }
4
+ end
@@ -0,0 +1,30 @@
1
+ module Spree
2
+ class Promotion
3
+ module Rules
4
+ class Store < PromotionRule
5
+ has_and_belongs_to_many :stores, :class_name => 'Spree::Store', :join_table => 'spree_promotion_rules_stores', :foreign_key => 'promotion_rule_id'
6
+
7
+ def applicable?(promotable)
8
+ promotable.is_a?(Spree::Order)
9
+ end
10
+
11
+ def eligible?(order, options = {})
12
+ stores.none? or stores.include?(order.store)
13
+ end
14
+
15
+ def applicable?(promotable)
16
+ promotable.is_a?(Spree::Order)
17
+ end
18
+
19
+ def store_ids_string
20
+ store_ids.join(',')
21
+ end
22
+
23
+ def store_ids_string=(s)
24
+ self.store_ids = s.to_s.split(',').map(&:strip)
25
+ end
26
+
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,18 @@
1
+ Spree::ShippingMethod.class_eval do
2
+ has_many :store_shipping_methods
3
+ has_many :stores, :through => :store_shipping_methods
4
+
5
+ # This adds store_match to the list of requirements.
6
+ # This will need to be fixed for Spree 2.0 when split shipments is added
7
+ def available_to_order?(order, display_on= nil)
8
+ available?(order, display_on) &&
9
+ within_zone?(order) &&
10
+ category_match?(order) &&
11
+ currency_match?(order) &&
12
+ store_match?(order)
13
+ end
14
+
15
+ def store_match?(order)
16
+ order.store.shipping_methods.empty? || stores.include?(order.store)
17
+ end
18
+ end