spree_group_buy 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.rspec +3 -0
- data/.rubocop.yml +24 -0
- data/.travis.yml +49 -0
- data/Appraisals +20 -0
- data/Gemfile +11 -0
- data/LICENSE +26 -0
- data/README.md +51 -0
- data/Rakefile +21 -0
- data/app/.gitkeep +0 -0
- data/app/controllers/.gitkeep +0 -0
- data/app/controllers/spree/admin/group_buys_controller.rb +15 -0
- data/app/controllers/spree/admin/orders_controller_decorator.rb +17 -0
- data/app/controllers/spree/api/v2/storefront/cart_controller_decorator.rb +9 -0
- data/app/controllers/spree/products_controller_decorator.rb +20 -0
- data/app/mailers/spree/order_mailer_decorator.rb +10 -0
- data/app/models/.gitkeep +0 -0
- data/app/models/spree/group_buy.rb +72 -0
- data/app/models/spree/line_item_decorator.rb +18 -0
- data/app/models/spree/order_decorator.rb +68 -0
- data/app/models/spree/product_decorator.rb +8 -0
- data/app/models/spree/stock/packer_decorator.rb +27 -0
- data/app/models/spree/stock/prioritizer_decorator.rb +18 -0
- data/app/services/.gitkeep +0 -0
- data/app/services/spree/cart/group_buy_add_item.rb +66 -0
- data/app/views/.gitkeep +0 -0
- data/app/views/spree/admin/group_buys/_form.html.erb +32 -0
- data/app/views/spree/admin/group_buys/edit.html.erb +13 -0
- data/app/views/spree/admin/group_buys/index.html.erb +49 -0
- data/app/views/spree/admin/group_buys/new.html.erb +15 -0
- data/app/views/spree/admin/orders/index.html.erb +271 -0
- data/app/views/spree/admin/shared/_main_menu.html.erb +49 -0
- data/app/views/spree/admin/shared/_product_tabs.html.erb +56 -0
- data/bin/rails +8 -0
- data/config/locales/en.yml +5 -0
- data/config/routes.rb +8 -0
- data/db/migrate/20200824192531_create_spree_group_buys.rb +15 -0
- data/db/migrate/20200826140754_add_group_buy_to_line_items.rb +5 -0
- data/db/migrate/20201005210530_add_group_buy_to_orders.rb +5 -0
- data/gemfiles/spree_3_7.gemfile +9 -0
- data/gemfiles/spree_4_0.gemfile +8 -0
- data/gemfiles/spree_4_1.gemfile +9 -0
- data/gemfiles/spree_master.gemfile +8 -0
- data/lib/generators/spree_group_buy/install/install_generator.rb +26 -0
- data/lib/generators/templates/vendor/assets/javascripts/spree/frontend/views/spree/products/cart_form.js +388 -0
- data/lib/generators/templates/vendor/assets/javascripts/spree/frontend/views/spree/shared/product_added_modal.js +28 -0
- data/lib/spree_group_buy.rb +4 -0
- data/lib/spree_group_buy/engine.rb +20 -0
- data/lib/spree_group_buy/factories.rb +6 -0
- data/lib/spree_group_buy/version.rb +17 -0
- data/spree_group_buy.gemspec +32 -0
- metadata +197 -0
checksums.yaml
ADDED
@@ -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
|
data/.gitignore
ADDED
@@ -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
data/.rubocop.yml
ADDED
@@ -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
|
data/.travis.yml
ADDED
@@ -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
|
data/Appraisals
ADDED
@@ -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.
|
data/README.md
ADDED
@@ -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
|
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'] = 'spree_group_buy'
|
20
|
+
Rake::Task['extension:test_app'].invoke
|
21
|
+
end
|
data/app/.gitkeep
ADDED
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,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
|
data/app/models/.gitkeep
ADDED
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
|