spree_group_buy 0.0.1

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 (53) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +24 -0
  5. data/.travis.yml +49 -0
  6. data/Appraisals +20 -0
  7. data/Gemfile +11 -0
  8. data/LICENSE +26 -0
  9. data/README.md +51 -0
  10. data/Rakefile +21 -0
  11. data/app/.gitkeep +0 -0
  12. data/app/controllers/.gitkeep +0 -0
  13. data/app/controllers/spree/admin/group_buys_controller.rb +15 -0
  14. data/app/controllers/spree/admin/orders_controller_decorator.rb +17 -0
  15. data/app/controllers/spree/api/v2/storefront/cart_controller_decorator.rb +9 -0
  16. data/app/controllers/spree/products_controller_decorator.rb +20 -0
  17. data/app/mailers/spree/order_mailer_decorator.rb +10 -0
  18. data/app/models/.gitkeep +0 -0
  19. data/app/models/spree/group_buy.rb +72 -0
  20. data/app/models/spree/line_item_decorator.rb +18 -0
  21. data/app/models/spree/order_decorator.rb +68 -0
  22. data/app/models/spree/product_decorator.rb +8 -0
  23. data/app/models/spree/stock/packer_decorator.rb +27 -0
  24. data/app/models/spree/stock/prioritizer_decorator.rb +18 -0
  25. data/app/services/.gitkeep +0 -0
  26. data/app/services/spree/cart/group_buy_add_item.rb +66 -0
  27. data/app/views/.gitkeep +0 -0
  28. data/app/views/spree/admin/group_buys/_form.html.erb +32 -0
  29. data/app/views/spree/admin/group_buys/edit.html.erb +13 -0
  30. data/app/views/spree/admin/group_buys/index.html.erb +49 -0
  31. data/app/views/spree/admin/group_buys/new.html.erb +15 -0
  32. data/app/views/spree/admin/orders/index.html.erb +271 -0
  33. data/app/views/spree/admin/shared/_main_menu.html.erb +49 -0
  34. data/app/views/spree/admin/shared/_product_tabs.html.erb +56 -0
  35. data/bin/rails +8 -0
  36. data/config/locales/en.yml +5 -0
  37. data/config/routes.rb +8 -0
  38. data/db/migrate/20200824192531_create_spree_group_buys.rb +15 -0
  39. data/db/migrate/20200826140754_add_group_buy_to_line_items.rb +5 -0
  40. data/db/migrate/20201005210530_add_group_buy_to_orders.rb +5 -0
  41. data/gemfiles/spree_3_7.gemfile +9 -0
  42. data/gemfiles/spree_4_0.gemfile +8 -0
  43. data/gemfiles/spree_4_1.gemfile +9 -0
  44. data/gemfiles/spree_master.gemfile +8 -0
  45. data/lib/generators/spree_group_buy/install/install_generator.rb +26 -0
  46. data/lib/generators/templates/vendor/assets/javascripts/spree/frontend/views/spree/products/cart_form.js +388 -0
  47. data/lib/generators/templates/vendor/assets/javascripts/spree/frontend/views/spree/shared/product_added_modal.js +28 -0
  48. data/lib/spree_group_buy.rb +4 -0
  49. data/lib/spree_group_buy/engine.rb +20 -0
  50. data/lib/spree_group_buy/factories.rb +6 -0
  51. data/lib/spree_group_buy/version.rb +17 -0
  52. data/spree_group_buy.gemspec +32 -0
  53. metadata +197 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5e2f5a859a4d295f634812219d0a0b372788d31d31fc8ba2cb4f91d44f8e2c56
4
+ data.tar.gz: 37b8d0f3284aa00a66e2a2849b09b7760592e5a11ccc9bfd38f02474f431c70d
5
+ SHA512:
6
+ metadata.gz: '09223f229d74a531ea269e814a2df0ed74ea0767027a0747d25bd6702793dc32f415b297ed6e8b1500965a3ef1274f7965d417563d9aef67d2e24c98c08329f5'
7
+ data.tar.gz: 9716a3648dc2d0d0d3e199f7c81992d8553ea8d902aa88027f25e6354239ccf9529e16013a0bda7dc30ed63d14c054db6f5ef8cc4c9f3e8dfece382609bf7d7b
@@ -0,0 +1,22 @@
1
+ \#*
2
+ *~
3
+ .#*
4
+ .DS_Store
5
+ .idea
6
+ .localeapp/locales
7
+ .project
8
+ .vscode
9
+ coverage
10
+ default
11
+ Gemfile.lock
12
+ tmp
13
+ nbproject
14
+ pkg
15
+ *.sw?
16
+ spec/dummy
17
+ .rvmrc
18
+ .sass-cache
19
+ public/spree
20
+ .ruby-version
21
+ .ruby-gemset
22
+ gemfiles/*.gemfile.lock
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ -r spec_helper
3
+ -f documentation
@@ -0,0 +1,24 @@
1
+ AllCops:
2
+ DisplayCopNames: true
3
+ TargetRubyVersion: 2.5
4
+ Include:
5
+ - '**/Gemfile'
6
+ - '**/Rakefile'
7
+ - '**/Appraisals'
8
+ Exclude:
9
+ - 'spec/dummy/**/*'
10
+ - 'lib/generators/**/*'
11
+
12
+ Rails:
13
+ Enabled: true
14
+
15
+ Metrics/LineLength:
16
+ Max: 150
17
+
18
+ # DISABLED
19
+
20
+ Style/Documentation:
21
+ Enabled: false
22
+
23
+ Style/FrozenStringLiteralComment:
24
+ Enabled: false
@@ -0,0 +1,49 @@
1
+ os: linux
2
+ dist: bionic
3
+
4
+ addons:
5
+ apt:
6
+ sources:
7
+ - google-chrome
8
+ packages:
9
+ - google-chrome-stable
10
+
11
+ services:
12
+ - mysql
13
+ - postgresql
14
+
15
+ language: ruby
16
+
17
+ rvm:
18
+ - 2.5
19
+ - 2.6
20
+
21
+ env:
22
+ - DB=mysql
23
+ - DB=postgres
24
+
25
+ gemfile:
26
+ - gemfiles/spree_3_7.gemfile
27
+ - gemfiles/spree_4_0.gemfile
28
+ - gemfiles/spree_4_1.gemfile
29
+ - gemfiles/spree_master.gemfile
30
+
31
+ jobs:
32
+ allow_failures:
33
+ - gemfile: gemfiles/spree_master.gemfile
34
+ exclude:
35
+ - rvm: 2.6
36
+ gemfile: gemfiles/spree_3_7.gemfile
37
+
38
+ before_install:
39
+ - mysql -u root -e "GRANT ALL ON *.* TO 'travis'@'%';"
40
+
41
+ before_script:
42
+ - CHROME_MAIN_VERSION=`google-chrome-stable --version | sed -E 's/(^Google Chrome |\.[0-9]+ )//g'`
43
+ - CHROMEDRIVER_VERSION=`curl -s "https://chromedriver.storage.googleapis.com/LATEST_RELEASE_$CHROME_MAIN_VERSION"`
44
+ - curl "https://chromedriver.storage.googleapis.com/${CHROMEDRIVER_VERSION}/chromedriver_linux64.zip" -O
45
+ - unzip chromedriver_linux64.zip -d ~/bin
46
+
47
+ script:
48
+ - bundle exec rake test_app
49
+ - bundle exec rake spec
@@ -0,0 +1,20 @@
1
+ appraise 'spree-3-7' do
2
+ gem 'spree', '~> 3.7.0'
3
+ gem 'sass-rails'
4
+ gem 'rails-controller-testing'
5
+ end
6
+
7
+ appraise 'spree-4-0' do
8
+ gem 'spree', '~> 4.0.0'
9
+ gem 'rails-controller-testing'
10
+ end
11
+
12
+ appraise 'spree-4-1' do
13
+ gem 'spree', '~> 4.1.0'
14
+ gem 'rails-controller-testing'
15
+ end
16
+
17
+ appraise 'spree-master' do
18
+ gem 'spree', github: 'spree/spree', branch: 'master'
19
+ gem 'rails-controller-testing'
20
+ end
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'https://rubygems.org'
2
+
3
+ git_source(:github) do |repo_name|
4
+ repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?('/')
5
+ "https://github.com/#{repo_name}.git"
6
+ end
7
+
8
+ gem 'spree', github: 'spree/spree', branch: 'master'
9
+ gem 'rails-controller-testing'
10
+
11
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,26 @@
1
+ Copyright (c) 2020 [name of plugin creator]
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,51 @@
1
+ # SpreeGroupBuy
2
+
3
+ Introduction goes here.
4
+
5
+ ## Installation
6
+
7
+ 1. Add this extension to your Gemfile with this line:
8
+
9
+ ```ruby
10
+ gem 'spree_group_buy', github: '[your-github-handle]/spree_group_buy'
11
+ ```
12
+
13
+ 2. Install the gem using Bundler
14
+
15
+ ```ruby
16
+ bundle install
17
+ ```
18
+
19
+ 3. Copy & run migrations
20
+
21
+ ```ruby
22
+ bundle exec rails g spree_group_buy:install
23
+ ```
24
+
25
+ 4. Restart your server
26
+
27
+ If your server was running, restart it so that it can find the assets properly.
28
+
29
+ ## Testing
30
+
31
+ 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`.
32
+
33
+ ```shell
34
+ bundle
35
+ bundle exec rake
36
+ ```
37
+
38
+ When testing your applications integration with this extension you may use it's factories.
39
+ Simply add this require statement to your spec_helper:
40
+
41
+ ```ruby
42
+ require 'spree_group_buy/factories'
43
+ ```
44
+
45
+ ## Contributing
46
+
47
+ If you'd like to contribute, please take a look at the
48
+ [instructions](CONTRIBUTING.md) for installing dependencies and crafting a good
49
+ pull request.
50
+
51
+ Copyright (c) 2020 [name of extension creator], released under the New BSD License
@@ -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'] = 'spree_group_buy'
20
+ Rake::Task['extension:test_app'].invoke
21
+ end
File without changes
File without changes
@@ -0,0 +1,15 @@
1
+ module Spree
2
+ module Admin
3
+ class GroupBuysController < ResourceController
4
+ belongs_to 'spree/product', find_by: :slug
5
+ before_action :find_group_buys, only: :index
6
+
7
+ private
8
+
9
+ def find_group_buys
10
+ @group_buys = @product.group_buys
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ module Spree::Admin::OrdersControllerDecorator
2
+
3
+ def resend
4
+ if @order.group_buy?
5
+ Spree::OrderMailer.groupbuy_confirm_email(@order.id, true).deliver_later
6
+ else
7
+ Spree::OrderMailer.confirm_email(@order.id, true).deliver_later
8
+ end
9
+ flash[:success] = Spree.t(:order_email_resent)
10
+
11
+ redirect_back fallback_location: spree.edit_admin_order_url(@order)
12
+ end
13
+
14
+
15
+ end
16
+
17
+ Spree::Admin::OrdersController.prepend Spree::Admin::OrdersControllerDecorator
@@ -0,0 +1,9 @@
1
+ module Spree::Api::V2::Storefront::CartControllerDecorator
2
+
3
+ def add_item_service
4
+ Spree::Cart::GroupBuyAddItem
5
+ end
6
+
7
+ end
8
+
9
+ Spree::Api::V2::Storefront::CartController.prepend Spree::Api::V2::Storefront::CartControllerDecorator
@@ -0,0 +1,20 @@
1
+ module Spree::ProductsControllerDecorator
2
+
3
+ def show
4
+ redirect_if_legacy_path
5
+
6
+ @taxon = params[:taxon_id].present? ? Spree::Taxon.find(params[:taxon_id]) : @product.taxons.first
7
+
8
+ if stale?(etag: product_etag, last_modified: @product.updated_at.utc, public: true)
9
+ @product_summary = Spree::ProductSummaryPresenter.new(@product).call
10
+ @product_properties = @product.product_properties.includes(:property)
11
+ @product_price = @product.price_in(current_currency).amount
12
+ load_variants
13
+ @product_images = product_images(@product, @variants)
14
+ @product_group_buys = @product.active_group_buys
15
+ end
16
+ end
17
+
18
+ end
19
+
20
+ Spree::ProductsController.prepend Spree::ProductsControllerDecorator
@@ -0,0 +1,10 @@
1
+ module Spree::OrderMailerDecorator
2
+ def groupbuy_confirm_email(order, resend = false)
3
+ @order = order.respond_to?(:id) ? order : Spree::Order.find(order)
4
+ subject = (resend ? "[#{Spree.t(:resend).upcase}] " : '')
5
+ subject += "#{Spree::Store.current.name} Group Buy #{Spree.t('order_mailer.confirm_email.subject')} ##{@order.number}"
6
+ mail(to: @order.email, from: from_address, subject: subject)
7
+ end
8
+ end
9
+
10
+ Spree::OrderMailer.prepend Spree::OrderMailerDecorator
File without changes
@@ -0,0 +1,72 @@
1
+ module Spree
2
+ class GroupBuy < Spree::Base
3
+
4
+ belongs_to :product, touch: true
5
+ has_many :line_items
6
+ has_many :orders, through: :line_items
7
+
8
+ scope :active, -> { where(state: 'active') }
9
+
10
+ before_validation :set_currency
11
+
12
+ def display_price
13
+ Spree::Money.new(price || 0, currency: currency)
14
+ end
15
+
16
+ def completed_orders
17
+ orders.select(&:completed?)
18
+ end
19
+
20
+ def completed_pending_orders
21
+ orders.select { |o| o.completed? and o.payment_state == "balance_due" }
22
+ end
23
+
24
+ def completed_paid_orders
25
+ orders.select { |o| o.completed? and o.payment_state == "paid" }
26
+ end
27
+
28
+ def active?
29
+ state == 'active'
30
+ end
31
+
32
+ def capture_payments!
33
+ completed_pending_orders.each do |order|
34
+ order.payments.each do |payment|
35
+ payment.send("capture!")
36
+ end
37
+ end
38
+ end
39
+
40
+ def void_payments!
41
+ completed_pending_orders.each do |order|
42
+ order.payments.each do |payment|
43
+ payment.send("void_transaction!")
44
+ end
45
+ end
46
+ end
47
+
48
+ def is_expired?
49
+ expires_at < DateTime.now
50
+ end
51
+
52
+ def goal_accomplished?
53
+ completed_pending_orders.length >= quantity
54
+ end
55
+
56
+ def set_accomplished!
57
+ update_column(:state, 'accomplished')
58
+ end
59
+
60
+ def set_failed!
61
+ update_column(:state, 'failed')
62
+ end
63
+
64
+
65
+ private
66
+
67
+ def set_currency
68
+ self.currency = Spree::Config[:currency] if currency.blank?
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,18 @@
1
+ module Spree::LineItemDecorator
2
+ def self.prepended(base)
3
+ base.belongs_to :group_buy, class_name: 'Spree::GroupBuy'
4
+ end
5
+
6
+ include Spree::VatPriceCalculation
7
+
8
+ def update_price
9
+ if group_buy_id?
10
+ self.price = gross_amount(group_buy.price, {tax_zone: tax_zone, tax_category: variant.tax_category})
11
+ else
12
+ self.price = variant.price_including_vat_for(tax_zone: tax_zone)
13
+ end
14
+ end
15
+
16
+ end
17
+
18
+ Spree::LineItem.prepend Spree::LineItemDecorator
@@ -0,0 +1,68 @@
1
+ module Spree::OrderDecorator
2
+
3
+ def self.prepended(base)
4
+ base.whitelisted_ransackable_attributes = %w[completed_at email number state payment_state shipment_state total considered_risky group_buy channel]
5
+ end
6
+
7
+ def update_line_item_prices!
8
+ transaction do
9
+ line_items.reload.each(&:update_price)
10
+ save!
11
+ end
12
+
13
+ check_group_buy
14
+ end
15
+
16
+ def finalize!
17
+ # lock all adjustments (coupon promotions, etc.)
18
+ all_adjustments.each(&:close)
19
+
20
+ # update payment and shipment(s) states, and save
21
+ updater.update_payment_state
22
+ shipments.each do |shipment|
23
+ shipment.update!(self)
24
+ shipment.finalize!
25
+ end
26
+
27
+ updater.update_shipment_state
28
+ save!
29
+ updater.run_hooks
30
+
31
+ touch :completed_at
32
+
33
+ if group_buy
34
+ deliver_groupbuy_order_confirmation_email unless confirmation_delivered?
35
+ else
36
+ deliver_order_confirmation_email unless confirmation_delivered?
37
+ end
38
+
39
+ consider_risk
40
+ end
41
+
42
+ def deliver_groupbuy_order_confirmation_email
43
+ Spree::OrderMailer.groupbuy_confirm_email(id).deliver_later
44
+ update_column(:confirmation_delivered, true)
45
+ end
46
+
47
+ def check_group_buy
48
+ update_column(:group_buy, is_group_buy?)
49
+ end
50
+
51
+ def is_group_buy?
52
+ line_items.each do |line_item|
53
+ return true if line_item.group_buy_id?
54
+ end
55
+ return false
56
+ end
57
+
58
+ # if it is group buy order then just authorize, otherwise purchase
59
+ def process_payments!
60
+ if group_buy
61
+ process_payments_with(:authorize!)
62
+ else
63
+ process_payments_with(:purchase!)
64
+ end
65
+ end
66
+ end
67
+
68
+ Spree::Order.prepend Spree::OrderDecorator