spree_group_buy 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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