solidus_product_assembly 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/.rspec +3 -0
- data/.travis.yml +21 -0
- data/Gemfile +18 -0
- data/LICENSE.md +13 -0
- data/README.md +80 -0
- data/Rakefile +21 -0
- data/app/assets/images/spinner.gif +0 -0
- data/app/assets/javascripts/spree/backend/solidus_product_assembly.js +1 -0
- data/app/assets/javascripts/spree/frontend/solidus_product_assembly.js +1 -0
- data/app/assets/stylesheets/spree/backend/solidus_product_assembly.css +3 -0
- data/app/assets/stylesheets/spree/frontend/solidus_product_assembly.css +3 -0
- data/app/controllers/spree/admin/parts_controller.rb +49 -0
- data/app/controllers/spree/checkout_controller_decorator.rb +9 -0
- data/app/helpers/spree/admin/orders_helper_decorator.rb +9 -0
- data/app/models/spree/assemblies_part.rb +12 -0
- data/app/models/spree/inventory_unit_decorator.rb +13 -0
- data/app/models/spree/line_item_decorator.rb +44 -0
- data/app/models/spree/order_inventory_assembly.rb +39 -0
- data/app/models/spree/product_decorator.rb +56 -0
- data/app/models/spree/shipment_decorator.rb +50 -0
- data/app/models/spree/stock/availability_validator.rb +28 -0
- data/app/models/spree/stock/inventory_unit_builder_decorator.rb +30 -0
- data/app/models/spree/stock/inventory_validator_decorator.rb +12 -0
- data/app/models/spree/variant_decorator.rb +13 -0
- data/app/overrides/add_admin_product_form_fields.rb +5 -0
- data/app/overrides/add_admin_tabs.rb +5 -0
- data/app/overrides/add_line_item_description.rb +5 -0
- data/app/overrides/spree/admin/orders/_form/inject_product_assemblies.html.erb.deface +3 -0
- data/app/overrides/spree/admin/orders/_shipment/stock_contents.html.erb.deface +2 -0
- data/app/overrides/spree/checkout/_delivery/remove_unshippable_markup.html.erb.deface +1 -0
- data/app/overrides/spree/checkout/_delivery/render_line_item_manifest.html.erb.deface +3 -0
- data/app/overrides/spree/products/show/add_links_to_parts.html.erb.deface +21 -0
- data/app/overrides/spree/products/show/remove_add_to_cart_button_for_non_individual_sale_products.html.erb.deface +4 -0
- data/app/overrides/spree/shared/_order_details/part_description.html.erb.deface +8 -0
- data/app/views/spree/admin/orders/_assemblies.html.erb +56 -0
- data/app/views/spree/admin/orders/_stock_contents.html.erb +69 -0
- data/app/views/spree/admin/orders/_stock_item.html.erb +46 -0
- data/app/views/spree/admin/parts/_parts_table.html.erb +33 -0
- data/app/views/spree/admin/parts/available.html.erb +55 -0
- data/app/views/spree/admin/parts/available.js.erb +54 -0
- data/app/views/spree/admin/parts/index.html.erb +70 -0
- data/app/views/spree/admin/parts/update_parts_table.js.erb +2 -0
- data/app/views/spree/admin/products/_product_assembly_fields.html.erb +23 -0
- data/app/views/spree/admin/shared/_product_assembly_product_tabs.html.erb +3 -0
- data/app/views/spree/checkout/_line_item_manifest.html.erb +17 -0
- data/app/views/spree/orders/_cart_description.html.erb +8 -0
- data/bin/rails +7 -0
- data/config/locales/en.yml +14 -0
- data/config/locales/fr.yml +12 -0
- data/config/locales/ru.yml +12 -0
- data/config/locales/sv.yml +12 -0
- data/config/routes.rb +19 -0
- data/db/migrate/20091028152124_add_many_to_many_relation_to_products.rb +13 -0
- data/db/migrate/20091029165620_add_parts_fields_to_products.rb +27 -0
- data/db/migrate/20120316141830_namespace_product_assembly_for_spree_one.rb +9 -0
- data/db/migrate/20140620223938_add_id_to_spree_assemblies_parts.rb +9 -0
- data/lib/generators/solidus_product_assembly/install/install_generator.rb +24 -0
- data/lib/solidus_product_assembly.rb +3 -0
- data/lib/solidus_product_assembly/engine.rb +15 -0
- data/lib/solidus_product_assembly/version.rb +3 -0
- data/lib/tasks/spree2_upgrade.rake +29 -0
- data/solidus_product_assembly.gemspec +35 -0
- data/spec/features/admin/orders_spec.rb +29 -0
- data/spec/features/admin/parts_spec.rb +28 -0
- data/spec/features/checkout_spec.rb +92 -0
- data/spec/models/spree/assemblies_part_spec.rb +18 -0
- data/spec/models/spree/inventory_unit_spec.rb +32 -0
- data/spec/models/spree/line_item_spec.rb +72 -0
- data/spec/models/spree/order_contents_spec.rb +40 -0
- data/spec/models/spree/order_inventory_assembly_spec.rb +55 -0
- data/spec/models/spree/order_inventory_spec.rb +35 -0
- data/spec/models/spree/product_spec.rb +35 -0
- data/spec/models/spree/shipment_spec.rb +112 -0
- data/spec/models/spree/stock/availability_validator_spec.rb +71 -0
- data/spec/models/spree/stock/coordinator_spec.rb +52 -0
- data/spec/models/spree/stock/inventory_unit_builder_spec.rb +36 -0
- data/spec/models/spree/variant_spec.rb +28 -0
- data/spec/spec_helper.rb +57 -0
- data/spec/support/shared_contexts/order_with_bundle.rb +13 -0
- metadata +272 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 89f3f4fbf3c8638a1d3a0eb8daeec71ab2e0be2c
|
4
|
+
data.tar.gz: e67518d457ee0aa60495099b41e058b917f36472
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a4dae9aac9db62b23daca17315e84596f8da6421269ba816e8f17b6ac100e0c5916692d09e5f701c69b09972f65afe538fb231bd325bbf6e37690d48e8827c25
|
7
|
+
data.tar.gz: ff2051e5a167ef6f1d4d7fce18d302baef6952e94f22df48115242ee5e9d9037170e93b99ab47e91ebd794e115dba79527db152c174ffd6f4659cdabcdb96003
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
sudo: false
|
2
|
+
cache: bundler
|
3
|
+
language: ruby
|
4
|
+
rvm:
|
5
|
+
- 2.3.1
|
6
|
+
env:
|
7
|
+
matrix:
|
8
|
+
- SOLIDUS_BRANCH=v1.0 DB=postgres
|
9
|
+
- SOLIDUS_BRANCH=v1.1 DB=postgres
|
10
|
+
- SOLIDUS_BRANCH=v1.2 DB=postgres
|
11
|
+
- SOLIDUS_BRANCH=v1.3 DB=postgres
|
12
|
+
- SOLIDUS_BRANCH=v1.4 DB=postgres
|
13
|
+
- SOLIDUS_BRANCH=v2.0 DB=postgres
|
14
|
+
- SOLIDUS_BRANCH=master DB=postgres
|
15
|
+
- SOLIDUS_BRANCH=v1.0 DB=mysql
|
16
|
+
- SOLIDUS_BRANCH=v1.1 DB=mysql
|
17
|
+
- SOLIDUS_BRANCH=v1.2 DB=mysql
|
18
|
+
- SOLIDUS_BRANCH=v1.3 DB=mysql
|
19
|
+
- SOLIDUS_BRANCH=v1.4 DB=mysql
|
20
|
+
- SOLIDUS_BRANCH=v2.0 DB=mysql
|
21
|
+
- SOLIDUS_BRANCH=master DB=mysql
|
data/Gemfile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
branch = ENV.fetch('SOLIDUS_BRANCH', 'master')
|
4
|
+
gem "solidus", github: "solidusio/solidus", branch: branch
|
5
|
+
gem 'solidus_auth_devise'
|
6
|
+
|
7
|
+
if branch == 'master' || branch >= "v2.0"
|
8
|
+
gem "rails-controller-testing", group: :test
|
9
|
+
end
|
10
|
+
|
11
|
+
gem 'pg'
|
12
|
+
gem 'mysql2'
|
13
|
+
|
14
|
+
group :development, :test do
|
15
|
+
gem "pry-rails"
|
16
|
+
end
|
17
|
+
|
18
|
+
gemspec
|
data/LICENSE.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Spree Product Assembly License
|
2
|
+
==============================
|
3
|
+
|
4
|
+
Copyright © 2007-2014, Spree Commerce Inc. and other contributors.
|
5
|
+
All rights reserved.
|
6
|
+
|
7
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
8
|
+
|
9
|
+
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
10
|
+
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
11
|
+
* Neither the name of Spree Commerce Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
12
|
+
|
13
|
+
_This software is provided by the copyright holders and contributors "as is" and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the copyright owner of contributors be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage._
|
data/README.md
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
# Product Assembly
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/solidusio-contrib/solidus_product_assembly.svg?branch=master)](https://travis-ci.org/solidusio-contrib/solidus_product_assembly)
|
4
|
+
|
5
|
+
Create a product which is composed of other products.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add the following line to your `Gemfile`
|
10
|
+
```ruby
|
11
|
+
gem 'solidus_product_assembly', github: 'solidusio-contrib/solidus_product_assembly', branch: 'master'
|
12
|
+
```
|
13
|
+
|
14
|
+
Run bundle install as well as the extension intall command to copy and run migrations and
|
15
|
+
append solidus_product_assembly to your js manifest file
|
16
|
+
|
17
|
+
bundle install
|
18
|
+
rails g solidus_product_assembly:install
|
19
|
+
|
20
|
+
_master branch is compatible with spree edge and rails 4 only. Please use
|
21
|
+
2-0-stable for Spree 2.0.x or 1-3-stable branch for Spree 1.3.x compatibility_
|
22
|
+
|
23
|
+
_In case you're upgrading from 1-3-stable of this extension you might want to run a
|
24
|
+
rake task which assigns a line item to your previous inventory units from bundle
|
25
|
+
products. That is so you have a better view on the current backend UI and avoid
|
26
|
+
exceptions. No need to run this task if you're not upgrading from product assembly
|
27
|
+
1-3-stable_
|
28
|
+
|
29
|
+
rake solidus_product_assembly:upgrade
|
30
|
+
|
31
|
+
## Use
|
32
|
+
|
33
|
+
To build a bundle (assembly product) you'd need to first check the "Can be part"
|
34
|
+
flag on each product you want to be part of the bundle. Then create a product
|
35
|
+
and add parts to it. By doing that you're making that product an assembly.
|
36
|
+
|
37
|
+
The store will treat assemblies a bit different than regular products on checkout.
|
38
|
+
Spree will create and track inventory units for its parts rather than for the product itself.
|
39
|
+
That means you essentially have a product composed of other products. From a
|
40
|
+
customer perspective it's like they are paying a single amount for a collection
|
41
|
+
of products.
|
42
|
+
|
43
|
+
Contributing
|
44
|
+
------------
|
45
|
+
|
46
|
+
Spree is an open source project and we encourage contributions. Please see the [contributors guidelines][1] before contributing.
|
47
|
+
|
48
|
+
In the spirit of [free software][2], **everyone** is encouraged to help improve this project.
|
49
|
+
|
50
|
+
Here are some ways *you* can contribute:
|
51
|
+
|
52
|
+
* by using prerelease versions
|
53
|
+
* by reporting [bugs][3]
|
54
|
+
* by suggesting new features
|
55
|
+
* by writing translations
|
56
|
+
* by writing or editing documentation
|
57
|
+
* by writing specifications
|
58
|
+
* by writing code (*no patch is too small*: fix typos, add comments, clean up inconsistent whitespace)
|
59
|
+
* by refactoring code
|
60
|
+
* by resolving [issues][3]
|
61
|
+
* by reviewing patches
|
62
|
+
|
63
|
+
Starting point:
|
64
|
+
|
65
|
+
* Fork the repo
|
66
|
+
* Clone your repo
|
67
|
+
* Run `bundle install`
|
68
|
+
* Run `bundle exec rake test_app` to create the test application in `spec/test_app`
|
69
|
+
* Make your changes
|
70
|
+
* Ensure specs pass by running `bundle exec rspec spec`
|
71
|
+
* Submit your pull request
|
72
|
+
|
73
|
+
Copyright (c) 2014 [Spree Commerce Inc.][4] and [contributors][5], released under the [New BSD License][6]
|
74
|
+
|
75
|
+
[1]: http://guides.spreecommerce.com/developer/contributing.html
|
76
|
+
[2]: http://www.fsf.org/licensing/essays/free-sw.html
|
77
|
+
[3]: https://github.com/spree/spree-product-assembly/issues
|
78
|
+
[4]: https://github.com/spree
|
79
|
+
[5]: https://github.com/spree/spree-product-assembly/graphs/contributors
|
80
|
+
[6]: https://github.com/spree/spree-product-assembly/blob/master/LICENSE.md
|
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_product_assembly'
|
20
|
+
Rake::Task['common:test_app'].invoke("Spree::User")
|
21
|
+
end
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
//= require_tree .
|
@@ -0,0 +1 @@
|
|
1
|
+
//= require spree/frontend
|
@@ -0,0 +1,49 @@
|
|
1
|
+
class Spree::Admin::PartsController < Spree::Admin::BaseController
|
2
|
+
before_filter :find_product
|
3
|
+
|
4
|
+
def index
|
5
|
+
@parts = @product.parts
|
6
|
+
end
|
7
|
+
|
8
|
+
def remove
|
9
|
+
@part = Spree::Variant.find(params[:id])
|
10
|
+
@product.remove_part(@part)
|
11
|
+
render 'spree/admin/parts/update_parts_table'
|
12
|
+
end
|
13
|
+
|
14
|
+
def set_count
|
15
|
+
@part = Spree::Variant.find(params[:id])
|
16
|
+
@product.set_part_count(@part, params[:count].to_i)
|
17
|
+
render 'spree/admin/parts/update_parts_table'
|
18
|
+
end
|
19
|
+
|
20
|
+
def available
|
21
|
+
if params[:q].blank?
|
22
|
+
@available_products = []
|
23
|
+
else
|
24
|
+
query = "%#{params[:q]}%"
|
25
|
+
@available_products = Spree::Product.search_can_be_part(query)
|
26
|
+
@available_products.uniq!
|
27
|
+
end
|
28
|
+
respond_to do |format|
|
29
|
+
format.html {render :layout => false}
|
30
|
+
format.js {render :layout => false}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def create
|
35
|
+
@part = Spree::Variant.find(params[:part_id])
|
36
|
+
qty = params[:part_count].to_i
|
37
|
+
@product.add_part(@part, qty) if qty > 0
|
38
|
+
render 'spree/admin/parts/update_parts_table'
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
def find_product
|
43
|
+
@product = Spree::Product.find_by(slug: params[:product_id])
|
44
|
+
end
|
45
|
+
|
46
|
+
def model_class
|
47
|
+
Spree::AssembliesPart
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Spree
|
2
|
+
class AssembliesPart < ActiveRecord::Base
|
3
|
+
belongs_to :assembly, :class_name => "Spree::Product",
|
4
|
+
:foreign_key => "assembly_id", touch: true
|
5
|
+
|
6
|
+
belongs_to :part, :class_name => "Spree::Variant", :foreign_key => "part_id"
|
7
|
+
|
8
|
+
def self.get(assembly_id, part_id)
|
9
|
+
find_or_initialize_by(assembly_id: assembly_id, part_id: part_id)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Spree
|
2
|
+
InventoryUnit.class_eval do
|
3
|
+
def percentage_of_line_item
|
4
|
+
product = line_item.product
|
5
|
+
if product.assembly?
|
6
|
+
total_value = line_item.quantity_by_variant.map { |part, quantity| part.price * quantity }.sum
|
7
|
+
variant.price / total_value
|
8
|
+
else
|
9
|
+
1 / BigDecimal.new(line_item.quantity)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Spree
|
2
|
+
LineItem.class_eval do
|
3
|
+
scope :assemblies, -> { joins(:product => :parts).uniq }
|
4
|
+
|
5
|
+
def any_units_shipped?
|
6
|
+
inventory_units.any? { |unit| unit.shipped? }
|
7
|
+
end
|
8
|
+
|
9
|
+
# The parts that apply to this particular LineItem. Usually `product#parts`, but
|
10
|
+
# provided as a hook if you want to override and customize the parts for a specific
|
11
|
+
# LineItem.
|
12
|
+
def parts
|
13
|
+
product.parts
|
14
|
+
end
|
15
|
+
|
16
|
+
# The number of the specified variant that make up this LineItem. By default, calls
|
17
|
+
# `product#count_of`, but provided as a hook if you want to override and customize
|
18
|
+
# the parts available for a specific LineItem. Note that if you only customize whether
|
19
|
+
# a variant is included in the LineItem, and don't customize the quantity of that part
|
20
|
+
# per LineItem, you shouldn't need to override this method.
|
21
|
+
def count_of(variant)
|
22
|
+
product.count_of(variant)
|
23
|
+
end
|
24
|
+
|
25
|
+
def quantity_by_variant
|
26
|
+
if self.product.assembly?
|
27
|
+
{}.tap { |hash| self.product.assemblies_parts.each { |ap| hash[ap.part] = ap.count * self.quantity } }
|
28
|
+
else
|
29
|
+
{ self.variant => self.quantity }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
def update_inventory
|
35
|
+
if (changed? || target_shipment.present?) && self.order.has_checkout_step?("delivery")
|
36
|
+
if self.product.assembly?
|
37
|
+
OrderInventoryAssembly.new(self).verify(target_shipment)
|
38
|
+
else
|
39
|
+
OrderInventory.new(self.order, self).verify(target_shipment)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Spree
|
2
|
+
# This class has basically the same functionality of Spree core OrderInventory
|
3
|
+
# except that it takes account of bundle parts and properly creates and removes
|
4
|
+
# inventory unit for each parts of a bundle
|
5
|
+
class OrderInventoryAssembly < OrderInventory
|
6
|
+
attr_reader :product
|
7
|
+
|
8
|
+
def initialize(line_item)
|
9
|
+
@order = line_item.order
|
10
|
+
@line_item = line_item
|
11
|
+
@product = line_item.product
|
12
|
+
end
|
13
|
+
|
14
|
+
def verify(shipment = nil)
|
15
|
+
if order.completed? || shipment.present?
|
16
|
+
line_item.quantity_by_variant.each do |part, total_parts|
|
17
|
+
existing_parts = line_item.inventory_units.where(variant: part).count
|
18
|
+
|
19
|
+
self.variant = part
|
20
|
+
|
21
|
+
if existing_parts < total_parts
|
22
|
+
shipment = determine_target_shipment unless shipment
|
23
|
+
add_to_shipment(shipment, total_parts - existing_parts)
|
24
|
+
elsif existing_parts > total_parts
|
25
|
+
quantity = existing_parts - total_parts
|
26
|
+
if shipment.present?
|
27
|
+
remove_from_shipment(shipment, quantity)
|
28
|
+
else
|
29
|
+
order.shipments.each do |shipment|
|
30
|
+
break if quantity == 0
|
31
|
+
quantity -= remove_from_shipment(shipment, quantity)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
Spree::Product.class_eval do
|
2
|
+
has_and_belongs_to_many :parts, :class_name => "Spree::Variant",
|
3
|
+
:join_table => "spree_assemblies_parts",
|
4
|
+
:foreign_key => "assembly_id", :association_foreign_key => "part_id"
|
5
|
+
|
6
|
+
has_many :assemblies_parts, :class_name => "Spree::AssembliesPart",
|
7
|
+
:foreign_key => "assembly_id"
|
8
|
+
|
9
|
+
scope :individual_saled, -> { where(individual_sale: true) }
|
10
|
+
|
11
|
+
scope :search_can_be_part, ->(query){ not_deleted.available.joins(:master)
|
12
|
+
.where(arel_table["name"].matches("%#{query}%").or(Spree::Variant.arel_table["sku"].matches("%#{query}%")))
|
13
|
+
.where(can_be_part: true)
|
14
|
+
.limit(30)
|
15
|
+
}
|
16
|
+
|
17
|
+
validate :assembly_cannot_be_part, :if => :assembly?
|
18
|
+
|
19
|
+
def add_part(variant, count = 1)
|
20
|
+
set_part_count(variant, count_of(variant) + count)
|
21
|
+
end
|
22
|
+
|
23
|
+
def remove_part(variant)
|
24
|
+
set_part_count(variant, 0)
|
25
|
+
end
|
26
|
+
|
27
|
+
def set_part_count(variant, count)
|
28
|
+
ap = assemblies_part(variant)
|
29
|
+
if count > 0
|
30
|
+
ap.count = count
|
31
|
+
ap.save
|
32
|
+
else
|
33
|
+
ap.destroy
|
34
|
+
end
|
35
|
+
reload
|
36
|
+
end
|
37
|
+
|
38
|
+
def assembly?
|
39
|
+
parts.present?
|
40
|
+
end
|
41
|
+
|
42
|
+
def count_of(variant)
|
43
|
+
ap = assemblies_part(variant)
|
44
|
+
# This checks persisted because the default count is 1
|
45
|
+
ap.persisted? ? ap.count : 0
|
46
|
+
end
|
47
|
+
|
48
|
+
def assembly_cannot_be_part
|
49
|
+
errors.add(:can_be_part, Spree.t(:assembly_cannot_be_part)) if can_be_part
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
def assemblies_part(variant)
|
54
|
+
Spree::AssembliesPart.get(self.id, variant.id)
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Spree
|
2
|
+
Shipment.class_eval do
|
3
|
+
# Overriden from Spree core as a product bundle part should not be put
|
4
|
+
# together with an individual product purchased (even though they're the
|
5
|
+
# very same variant) That is so we can tell the store admin which units
|
6
|
+
# were purchased individually and which ones as parts of the bundle
|
7
|
+
#
|
8
|
+
# Account for situations where we can't track the line_item for a variant.
|
9
|
+
# This should avoid exceptions when users upgrade from spree 1.3
|
10
|
+
#
|
11
|
+
# TODO Can possibly be removed as well. We already override the manifest
|
12
|
+
# partial so we can get the product there
|
13
|
+
def manifest
|
14
|
+
items = []
|
15
|
+
inventory_units.joins(:variant).includes(:variant, :line_item).group_by(&:variant).each do |variant, units|
|
16
|
+
|
17
|
+
units.group_by(&:line_item).each do |line_item, units|
|
18
|
+
states = {}
|
19
|
+
units.group_by(&:state).each { |state, iu| states[state] = iu.count }
|
20
|
+
line_item ||= order.find_line_item_by_variant(variant)
|
21
|
+
|
22
|
+
part = line_item ? line_item.product.assembly? : false
|
23
|
+
items << OpenStruct.new(part: part,
|
24
|
+
product: line_item.try(:product),
|
25
|
+
line_item: line_item,
|
26
|
+
variant: variant,
|
27
|
+
quantity: units.length,
|
28
|
+
states: states)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
items
|
32
|
+
end
|
33
|
+
|
34
|
+
# There might be scenarios where we don't want to display every single
|
35
|
+
# variant on the shipment. e.g. when ordering a product bundle that includes
|
36
|
+
# 5 other parts. Frontend users should only see the product bundle as a
|
37
|
+
# single item to ship
|
38
|
+
def line_item_manifest
|
39
|
+
inventory_units.includes(:line_item, :variant).group_by(&:line_item).map do |line_item, units|
|
40
|
+
states = {}
|
41
|
+
units.group_by(&:state).each { |state, iu| states[state] = iu.count }
|
42
|
+
OpenStruct.new(line_item: line_item, variant: line_item.variant, quantity: units.length, states: states)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def inventory_units_for_item(line_item, variant)
|
47
|
+
inventory_units.where(line_item_id: line_item.id, variant_id: variant.id)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|