From f8b0a61bae978ec8ce1ffdbc2f2581737be8be3f Mon Sep 17 00:00:00 2001 From: KD Date: Fri, 7 Apr 2017 09:57:37 +0200 Subject: [PATCH 1/7] configure gemfiles --- .travis.yml | 4 ++-- Gemfile | 2 -- spree_product_assembly.gemspec | 19 ++++++++++--------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3351b5e2..7724e1c8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,5 +9,5 @@ before_script: script: - bundle exec rspec spec rvm: - - 2.2.4 - - 2.3.0 + - 2.2.5 + - 2.3.1 diff --git a/Gemfile b/Gemfile index 978cef5b..aa91e542 100644 --- a/Gemfile +++ b/Gemfile @@ -2,6 +2,4 @@ source "https://rubygems.org" gem 'spree', github: 'spree/spree', branch: 'master' -gem 'pry-rails' - gemspec diff --git a/spree_product_assembly.gemspec b/spree_product_assembly.gemspec index 3a0fc2d8..a5a7779f 100644 --- a/spree_product_assembly.gemspec +++ b/spree_product_assembly.gemspec @@ -17,18 +17,19 @@ Gem::Specification.new do |s| s.add_dependency 'spree_backend', '>= 3.1.0', '< 4.0' - s.add_development_dependency 'active_model_serializers', '~> 0.8.3' - s.add_development_dependency 'capybara', '~> 2.5' - s.add_development_dependency 'capybara-screenshot', '~> 1.0.11' - s.add_development_dependency 'coffee-rails', '~> 4.0.0' - s.add_development_dependency 'database_cleaner', '~> 1.4' - s.add_development_dependency 'factory_girl', '~> 4.4' + s.add_development_dependency 'active_model_serializers' + s.add_development_dependency 'capybara' + s.add_development_dependency 'capybara-screenshot' + s.add_development_dependency 'coffee-rails' + s.add_development_dependency 'database_cleaner' + s.add_development_dependency 'factory_girl' s.add_development_dependency 'ffaker' s.add_development_dependency 'launchy' s.add_development_dependency 'pg' - s.add_development_dependency 'poltergeist', '~> 1.6' - s.add_development_dependency 'rspec-rails', '~> 3.4.0' - s.add_development_dependency 'sass-rails', '~> 5.0.0' + s.add_development_dependency 'poltergeist' + s.add_development_dependency 'rspec-rails' + s.add_development_dependency 'sass-rails' s.add_development_dependency 'simplecov' s.add_development_dependency 'sqlite3' + s.add_development_dependency 'pry-rails' end From 202d48d2a51b8341bee1d5cf6c8ff4743f5473b5 Mon Sep 17 00:00:00 2001 From: KD Date: Fri, 7 Apr 2017 10:39:47 +0200 Subject: [PATCH 2/7] fix order items packing logic, fix order_spec.rb --- app/models/spree/order_decorator.rb | 14 +++++++++++ app/models/spree/stock/packer_decorator.rb | 24 +++++++++++++++++++ .../spree/stock/prioritizer_decorator.rb | 18 ++++++++++++++ spec/features/admin/orders_spec.rb | 2 ++ 4 files changed, 58 insertions(+) create mode 100644 app/models/spree/order_decorator.rb create mode 100644 app/models/spree/stock/packer_decorator.rb create mode 100644 app/models/spree/stock/prioritizer_decorator.rb diff --git a/app/models/spree/order_decorator.rb b/app/models/spree/order_decorator.rb new file mode 100644 index 00000000..f62923ca --- /dev/null +++ b/app/models/spree/order_decorator.rb @@ -0,0 +1,14 @@ +module Spree + Order.class_eval do + after_update :clean_inventory_units + + # during checkout each inventory_unit is saved twice + # second unit is not associated to shipment and is unnecessary + def clean_inventory_units + if state == 'delivery' + units = inventory_units.where(shipment: nil) + InventoryUnit.destroy(units.ids) if units.any? + end + end + end +end diff --git a/app/models/spree/stock/packer_decorator.rb b/app/models/spree/stock/packer_decorator.rb new file mode 100644 index 00000000..90d2d060 --- /dev/null +++ b/app/models/spree/stock/packer_decorator.rb @@ -0,0 +1,24 @@ +module Spree + module Stock + Packer.class_eval do + + def default_package + package = Package.new(stock_location) + + inventory_units.each do |inventory_unit| + variant = inventory_unit.variant + unit = inventory_unit.dup # Can be used by others, do not use directly + if variant.should_track_inventory? + next unless stock_location.stock_item(variant) + on_hand, backordered = stock_location.fill_status(variant, 1) + package.add(unit, :backordered) if backordered > 0 + package.add(unit, :on_hand) if on_hand > 0 + else + package.add unit + end + end + package + end + end + end +end \ No newline at end of file diff --git a/app/models/spree/stock/prioritizer_decorator.rb b/app/models/spree/stock/prioritizer_decorator.rb new file mode 100644 index 00000000..ba025ed7 --- /dev/null +++ b/app/models/spree/stock/prioritizer_decorator.rb @@ -0,0 +1,18 @@ +module Spree + module Stock + Prioritizer.class_eval do + + private + + def hash_item(item) + shipment = item.inventory_unit.shipment + inventory_unit = item.inventory_unit + if shipment.present? + inventory_unit.hash ^ shipment.hash + else + inventory_unit.hash + end + end + end + end +end \ No newline at end of file diff --git a/spec/features/admin/orders_spec.rb b/spec/features/admin/orders_spec.rb index 11509893..0fe409a0 100644 --- a/spec/features/admin/orders_spec.rb +++ b/spec/features/admin/orders_spec.rb @@ -9,8 +9,10 @@ background do bundle.master.parts << [parts] line_item.update_attributes!(quantity: 3) + order.next order.reload.create_proposed_shipments order.finalize! + order.reload end scenario "allows admin to edit product bundle" do From bf8e47473a2bb19a9b60e320f0c4bcf5e43248b6 Mon Sep 17 00:00:00 2001 From: KD Date: Fri, 7 Apr 2017 10:41:40 +0200 Subject: [PATCH 3/7] fix editing shipments items on admin panel --- app/models/spree/order_inventory_assembly.rb | 26 ++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/app/models/spree/order_inventory_assembly.rb b/app/models/spree/order_inventory_assembly.rb index 6f0a7334..6e91a86c 100644 --- a/app/models/spree/order_inventory_assembly.rb +++ b/app/models/spree/order_inventory_assembly.rb @@ -25,6 +25,32 @@ def verify(shipment = nil) private + def add_to_shipment(shipment, quantity) + units = shipment.inventory_units + if variant.should_track_inventory? + on_hand, back_order = shipment.stock_location.fill_status(variant, quantity) + + on_hand.times { units << set_up_invetory_unit('on_hand', variant, order, line_item) } + back_order.times { units << set_up_invetory_unit('backordered', variant, order, line_item) } + else + quantity.times { units << set_up_invetory_unit('on_hand', variant, order, line_item) } + end + + shipment.inventory_units = units + shipment.save + + # adding to this shipment, and removing from stock_location + if order.completed? + shipment.stock_location.unstock(variant, quantity, shipment) + end + + quantity + end + + def set_up_invetory_unit(state, variant, order, line_item) + InventoryUnit.new(state: state, variant_id: variant.id, order_id: order.id, line_item_id: line_item.id) + end + def verify_parts(shipment, total_parts, existing_parts) if existing_parts < total_parts verifiy_add_to_shipment(shipment, total_parts, existing_parts) From a57d09751f52c2b3ea7eb61bf41ed8db3a7b6703 Mon Sep 17 00:00:00 2001 From: KD Date: Fri, 7 Apr 2017 10:46:08 +0200 Subject: [PATCH 4/7] add additional test for calculating orders inventory units --- spec/models/spree/order_spec.rb | 56 +++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 spec/models/spree/order_spec.rb diff --git a/spec/models/spree/order_spec.rb b/spec/models/spree/order_spec.rb new file mode 100644 index 00000000..9614e28c --- /dev/null +++ b/spec/models/spree/order_spec.rb @@ -0,0 +1,56 @@ +module Spree + describe Order, type: :model do + + let(:order) { create(:order_with_line_items) } + let(:line_item) { order.line_items.first } + let(:bundle) { line_item.product } + let(:parts) { (1..3).map { create(:variant) } } + + before do + bundle.master.parts << [parts] + order.contents.update_cart({line_items_attributes: { + id: line_item.id, + quantity: 3, + options: {} + }}) + order.next + order.reload.create_proposed_shipments + order.finalize! + end + + context "product assembly is added to shipment of completed order" do + it "sets items number bigger than existing item number - adds inventory units to shipment package" do + order.contents.update_cart({line_items_attributes: { + id: line_item.id, + quantity: 4, + options: {} + }}) + + line_item_quantity = line_item.reload.quantity + units_quantity = 0 + order.reload.shipments.each { |s| units_quantity += s.inventory_units.count } + + expect(line_item_quantity).to eq(4) + expect(units_quantity).to eq(4 * 3) + end + end + + context "product assembly is removed from shipment of completed order" do + it "sets items number lower than existing item number - removes inventory units from shipment package" do + + order.contents.update_cart({line_items_attributes: { + id: line_item.id, + quantity: 1, + options: {} + }}) + + line_item_quantity = line_item.reload.quantity + units_quantity = 0 + order.reload.shipments.each { |s| units_quantity += s.inventory_units.count } + + expect(line_item_quantity).to eq(1) + expect(units_quantity).to eq(1 * 3) + end + end + end +end From 5c80ffd8da5a51c1bc350b3dd641ee620c5b6712 Mon Sep 17 00:00:00 2001 From: KD Date: Fri, 7 Apr 2017 11:58:13 +0200 Subject: [PATCH 5/7] fix multiple stock locaion issue - copy code from spree 3.2 --- .../spree/stock/coordinator_decorator.rb | 45 +++++++++++++++++++ app/models/spree/stock/packer_decorator.rb | 9 ++++ spec/features/admin/orders_spec.rb | 5 +-- 3 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 app/models/spree/stock/coordinator_decorator.rb diff --git a/app/models/spree/stock/coordinator_decorator.rb b/app/models/spree/stock/coordinator_decorator.rb new file mode 100644 index 00000000..71aa0625 --- /dev/null +++ b/app/models/spree/stock/coordinator_decorator.rb @@ -0,0 +1,45 @@ +module Spree + module Stock + Coordinator.class_eval do + attr_reader :allocated_inventory_units + + def initialize(order, inventory_units = nil) + @order = order + @inventory_units = inventory_units || InventoryUnitBuilder.new(order).units + @allocated_inventory_units = [] + end + + def build_packages(packages = Array.new) + stock_locations_with_requested_variants.each do |stock_location| + packer = build_packer(stock_location, unallocated_inventory_units) + packages += packer.packages + @allocated_inventory_units += packer.allocated_inventory_units + end + + packages + end + + private + + def unallocated_inventory_units + if inventory_units.map(&:id).include?(nil) + allocated_inventory_units.each do |allocated| + inventory_units.each_with_index do |unit, index| + if should_delete_item?(allocated, unit) + inventory_units.delete_at(index) + break + end + end + end + inventory_units + else + inventory_units - allocated_inventory_units + end + end + + def should_delete_item?(allocated, unit) + allocated.line_item_id == unit.line_item_id && allocated.variant_id == unit.variant_id + end + end + end +end diff --git a/app/models/spree/stock/packer_decorator.rb b/app/models/spree/stock/packer_decorator.rb index 90d2d060..41f39b11 100644 --- a/app/models/spree/stock/packer_decorator.rb +++ b/app/models/spree/stock/packer_decorator.rb @@ -1,6 +1,14 @@ module Spree module Stock Packer.class_eval do + attr_reader :allocated_inventory_units + + def initialize(stock_location, inventory_units, splitters = [Splitter::Base]) + @stock_location = stock_location + @inventory_units = inventory_units + @splitters = splitters + @allocated_inventory_units = [] + end def default_package package = Package.new(stock_location) @@ -16,6 +24,7 @@ def default_package else package.add unit end + allocated_inventory_units << unit end package end diff --git a/spec/features/admin/orders_spec.rb b/spec/features/admin/orders_spec.rb index 0fe409a0..fb6d728d 100644 --- a/spec/features/admin/orders_spec.rb +++ b/spec/features/admin/orders_spec.rb @@ -9,10 +9,7 @@ background do bundle.master.parts << [parts] line_item.update_attributes!(quantity: 3) - order.next - order.reload.create_proposed_shipments - order.finalize! - order.reload + order.create_proposed_shipments end scenario "allows admin to edit product bundle" do From 8c5396e2d975cee2697c2ac567a7bd5c453c1df6 Mon Sep 17 00:00:00 2001 From: KD Date: Fri, 7 Apr 2017 13:12:11 +0200 Subject: [PATCH 6/7] add appraisals --- .gitignore | 1 + .travis.yml | 33 +++++++++++++++++++++++++-------- Appraisals | 13 +++++++++++++ spree_product_assembly.gemspec | 1 + 4 files changed, 40 insertions(+), 8 deletions(-) create mode 100644 Appraisals diff --git a/.gitignore b/.gitignore index 47302a67..c2d5f548 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ Gemfile.lock coverage .ruby-gemset .ruby-version +gemfiles/*.gemfile.lock diff --git a/.travis.yml b/.travis.yml index 7724e1c8..97d97688 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,30 @@ --- +sudo: required +dist: trusty + language: ruby -sudo: false -cache: bundler -before_script: - - sh -e /etc/init.d/xvfb start - - export DISPLAY=:99.0 - - bundle exec rake test_app + +env: + - DB=postgres + - DB=mysql + +gemfile: + - gemfiles/spree_3_1.gemfile + - gemfiles/spree_3_2.gemfile + - gemfiles/spree_master.gemfile + script: - - bundle exec rspec spec + - bundle install + - bundle exec rake test_app + - bundle exec rake spec + rvm: - - 2.2.5 - 2.3.1 + - 2.2.5 + +addons: + apt: + packages: + - mysql-server-5.6 + - mysql-client-core-5.6 + - mysql-client-5.6 diff --git a/Appraisals b/Appraisals new file mode 100644 index 00000000..7a7bca55 --- /dev/null +++ b/Appraisals @@ -0,0 +1,13 @@ +appraise 'spree-3-1' do + gem 'spree', '~> 3.1.0' +end + +appraise 'spree-3-2' do + gem 'spree', '~> 3.2.0.alpha' + gem 'rails-controller-testing' +end + +appraise 'spree-master' do + gem 'spree', github: 'spree/spree', branch: 'master' + gem 'rails-controller-testing' +end diff --git a/spree_product_assembly.gemspec b/spree_product_assembly.gemspec index a5a7779f..625e0981 100644 --- a/spree_product_assembly.gemspec +++ b/spree_product_assembly.gemspec @@ -31,5 +31,6 @@ Gem::Specification.new do |s| s.add_development_dependency 'sass-rails' s.add_development_dependency 'simplecov' s.add_development_dependency 'sqlite3' + s.add_development_dependency 'mysql2' s.add_development_dependency 'pry-rails' end From ee7e61e9ba0638a1054476b67681ef0d3374aaad Mon Sep 17 00:00:00 2001 From: KD Date: Fri, 7 Apr 2017 16:00:43 +0200 Subject: [PATCH 7/7] fix tests --- .travis.yml | 1 - Appraisals | 2 +- app/models/spree/order_inventory_assembly.rb | 1 + gemfiles/spree_3_1.gemfile | 7 ++++ gemfiles/spree_3_2.gemfile | 8 ++++ gemfiles/spree_master.gemfile | 8 ++++ spec/features/admin/orders_spec.rb | 5 ++- .../spree/assign_part_to_bundle_form_spec.rb | 4 +- spec/models/spree/order_contents_spec.rb | 4 +- .../spree/order_inventory_assembly_spec.rb | 38 +++++++++++++------ spree_product_assembly.gemspec | 1 + 11 files changed, 59 insertions(+), 20 deletions(-) create mode 100644 gemfiles/spree_3_1.gemfile create mode 100644 gemfiles/spree_3_2.gemfile create mode 100644 gemfiles/spree_master.gemfile diff --git a/.travis.yml b/.travis.yml index 97d97688..8c8ad0c6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,6 @@ gemfile: - gemfiles/spree_master.gemfile script: - - bundle install - bundle exec rake test_app - bundle exec rake spec diff --git a/Appraisals b/Appraisals index 7a7bca55..1c5a9816 100644 --- a/Appraisals +++ b/Appraisals @@ -3,7 +3,7 @@ appraise 'spree-3-1' do end appraise 'spree-3-2' do - gem 'spree', '~> 3.2.0.alpha' + gem 'spree', '~> 3.2.0' gem 'rails-controller-testing' end diff --git a/app/models/spree/order_inventory_assembly.rb b/app/models/spree/order_inventory_assembly.rb index 6e91a86c..3df6be85 100644 --- a/app/models/spree/order_inventory_assembly.rb +++ b/app/models/spree/order_inventory_assembly.rb @@ -9,6 +9,7 @@ def initialize(line_item) @order = line_item.order @line_item = line_item @product = line_item.product + @variant = line_item.variant end def verify(shipment = nil) diff --git a/gemfiles/spree_3_1.gemfile b/gemfiles/spree_3_1.gemfile new file mode 100644 index 00000000..925b090b --- /dev/null +++ b/gemfiles/spree_3_1.gemfile @@ -0,0 +1,7 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "spree", "~> 3.1.0" + +gemspec :path => "../" diff --git a/gemfiles/spree_3_2.gemfile b/gemfiles/spree_3_2.gemfile new file mode 100644 index 00000000..844fc70a --- /dev/null +++ b/gemfiles/spree_3_2.gemfile @@ -0,0 +1,8 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "spree", "~> 3.2.0" +gem "rails-controller-testing" + +gemspec :path => "../" diff --git a/gemfiles/spree_master.gemfile b/gemfiles/spree_master.gemfile new file mode 100644 index 00000000..c382de2c --- /dev/null +++ b/gemfiles/spree_master.gemfile @@ -0,0 +1,8 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "spree", :github => "spree/spree", :branch => "master" +gem "rails-controller-testing" + +gemspec :path => "../" diff --git a/spec/features/admin/orders_spec.rb b/spec/features/admin/orders_spec.rb index fb6d728d..3aaad281 100644 --- a/spec/features/admin/orders_spec.rb +++ b/spec/features/admin/orders_spec.rb @@ -8,8 +8,9 @@ background do bundle.master.parts << [parts] - line_item.update_attributes!(quantity: 3) - order.create_proposed_shipments + line_item.reload.update_attributes!(quantity: 3) + order.reload.create_proposed_shipments + order.finalize! end scenario "allows admin to edit product bundle" do diff --git a/spec/models/spree/assign_part_to_bundle_form_spec.rb b/spec/models/spree/assign_part_to_bundle_form_spec.rb index 61fd58dd..acf001b1 100644 --- a/spec/models/spree/assign_part_to_bundle_form_spec.rb +++ b/spec/models/spree/assign_part_to_bundle_form_spec.rb @@ -17,7 +17,7 @@ module Spree bundle = create(:product) part = create(:product, can_be_part: true) assignment = AssembliesPart.create( - assembly_id: bundle.id, + assembly_id: bundle.master.id, count: 1, part_id: part.id ) @@ -37,7 +37,7 @@ module Spree bundle = create(:product) part = create(:product, can_be_part: true) - part_options = { count: 2, part_id: part.id, assembly_id: bundle.id } + part_options = { count: 2, part_id: part.id, assembly_id: bundle.master.id } command = AssignPartToBundleForm.new(bundle, part_options) diff --git a/spec/models/spree/order_contents_spec.rb b/spec/models/spree/order_contents_spec.rb index 5933b390..c6bb6a82 100644 --- a/spec/models/spree/order_contents_spec.rb +++ b/spec/models/spree/order_contents_spec.rb @@ -50,10 +50,10 @@ create(:variant_in_stock, product: shirt, option_values: [blue_option]) assembly_part_keychain = create(:assemblies_part, - assembly_id: assembly.id, + assembly_id: assembly.master.id, part_id: keychain.master.id) assembly_part_shirt = create(:assemblies_part, - assembly_id: assembly.id, + assembly_id: assembly.master.id, part_id: shirt.master.id, variant_selection_deferred: true) assembly.reload diff --git a/spec/models/spree/order_inventory_assembly_spec.rb b/spec/models/spree/order_inventory_assembly_spec.rb index b7c087de..d8f95742 100644 --- a/spec/models/spree/order_inventory_assembly_spec.rb +++ b/spec/models/spree/order_inventory_assembly_spec.rb @@ -146,30 +146,44 @@ module Spree line_item_quantity: 2, parts: [{ count: 1 }, { count: 1 }, { count: 3 }] ) + shipped_shipment = create(:shipment, state: 'shipped') - InventoryUnit.all[0..2].each do |unit| + shipped_variant = variants.first + shipped = InventoryUnit.where(variant: shipped_variant) + + shipped.each do |unit| unit.update_attribute(:shipment_id, shipped_shipment.id) + unit.update_attribute(:state, 'shipped') end - inventory = OrderInventoryAssembly.new(line_item) + new_quantity = 1 - line_item.update_column(:quantity, 1) - inventory.verify + line_item.update_column(:quantity, new_quantity) + line_item.reload - expect(inventory.inventory_units.count).to eq 6 + inventory = OrderInventoryAssembly.new(line_item) + inventory.verify unshipped_units = unshipped_shipment.inventory_units - expect(unshipped_units.count).to eq 3 + shipped_units = shipped_shipment.inventory_units + + units_last_variant = new_quantity * variants.last.assemblies_variants.first.count + units_second_variant = new_quantity * variants.second.assemblies_variants.first.count + units_first_variant = shipped.count + + expected_units_count = units_first_variant + units_second_variant + units_last_variant + + expect(inventory.inventory_units.count).to eq expected_units_count + + expect(unshipped_units.count).to eq(expected_units_count - shipped.count) unshipped_units.each do |unit| - expect(unit.variant).to eq variants[2] + expect(unit.variant).not_to eq shipped_variant end - shipped_units = shipped_shipment.inventory_units - expect(shipped_units.count).to eq 3 - shipped_units[0..1].each do |unit| - expect(unit.variant).to eq variants[0] + expect(shipped_units.count).to eq(shipped.count) + shipped_units.each do |unit| + expect(unit.variant).to eq shipped_variant end - expect(shipped_units[2].variant).to eq variants[1] end end end diff --git a/spree_product_assembly.gemspec b/spree_product_assembly.gemspec index 625e0981..70b7993f 100644 --- a/spree_product_assembly.gemspec +++ b/spree_product_assembly.gemspec @@ -33,4 +33,5 @@ Gem::Specification.new do |s| s.add_development_dependency 'sqlite3' s.add_development_dependency 'mysql2' s.add_development_dependency 'pry-rails' + s.add_development_dependency 'appraisal' end