From e0f9894b7a13bb9fd1cd584a278e2dc2df207d44 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 16:18:02 +0100 Subject: [PATCH] Bring packer from spree_core --- app/models/spree/stock/packer.rb | 48 ++++++++++++ spec/models/spree/stock/packer_spec.rb | 102 +++++++++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 app/models/spree/stock/packer.rb create mode 100644 spec/models/spree/stock/packer_spec.rb diff --git a/app/models/spree/stock/packer.rb b/app/models/spree/stock/packer.rb new file mode 100644 index 0000000000..2dc5a67b9c --- /dev/null +++ b/app/models/spree/stock/packer.rb @@ -0,0 +1,48 @@ +module Spree + module Stock + class Packer + attr_reader :stock_location, :order, :splitters, :package_factory + + def initialize(stock_location, order, splitters=[Splitter::Base]) + @stock_location = stock_location + @order = order + @splitters = splitters + @package_factory = Spree::Config.package_factory + end + + def packages + if splitters.empty? + [default_package] + else + build_splitter.split [default_package] + end + end + + def default_package + package = package_factory.new(stock_location, order) + order.line_items.each do |line_item| + if Config.track_inventory_levels + next unless stock_location.stock_item(line_item.variant) + + on_hand, backordered = stock_location.fill_status(line_item.variant, line_item.quantity) + package.add line_item.variant, on_hand, :on_hand if on_hand > 0 + package.add line_item.variant, backordered, :backordered if backordered > 0 + else + package.add line_item.variant, line_item.quantity, :on_hand + end + end + package + end + + private + + def build_splitter + splitter = nil + splitters.reverse.each do |klass| + splitter = klass.new(self, splitter) + end + splitter + end + end + end +end diff --git a/spec/models/spree/stock/packer_spec.rb b/spec/models/spree/stock/packer_spec.rb new file mode 100644 index 0000000000..34259e1c43 --- /dev/null +++ b/spec/models/spree/stock/packer_spec.rb @@ -0,0 +1,102 @@ +require 'spec_helper' + +module Spree + module Stock + describe Packer do + let(:order) { create(:order_with_line_items, line_items_count: 5) } + let(:stock_location) { create(:stock_location) } + + subject { Packer.new(stock_location, order) } + + before do + Spree::Config.stub(:package_factory) { Package } + end + + context 'packages' do + it 'builds an array of packages' do + packages = subject.packages + packages.size.should eq 1 + packages.first.contents.size.should eq 5 + end + + it 'allows users to set splitters to an empty array' do + packages = Packer.new(stock_location, order, []).packages + packages.size.should eq 1 + end + end + + context 'default_package' do + it 'contains all the items' do + package = subject.default_package + package.contents.size.should eq 5 + package.weight.should > 0 + end + + it 'variants are added as backordered without enough on_hand' do + stock_location.should_receive(:fill_status).exactly(5).times.and_return([2,3]) + + package = subject.default_package + package.on_hand.size.should eq 5 + package.backordered.size.should eq 5 + end + + context 'when a packer factory is not specified' do + let(:package) { double(:package, add: true) } + + it 'calls Spree::Stock::Package' do + Package + .should_receive(:new) + .with(stock_location, order) + .and_return(package) + + subject.default_package + end + end + + context 'when a packer factory is specified' do + before do + Spree::Config.stub(:package_factory) { TestPackageFactory } + end + + class TestPackageFactory; end + + let(:package) { double(:package, add: true) } + + it 'calls the specified factory' do + TestPackageFactory + .should_receive(:new) + .with(stock_location, order) + .and_return(package) + + subject.default_package + end + end + + context "location doesn't have order items in stock" do + let(:stock_location) { create(:stock_location, propagate_all_variants: false) } + let(:packer) { Packer.new(stock_location, order) } + + it "builds an empty package" do + packer.default_package.contents.should be_empty + end + end + + context "doesn't track inventory levels" do + let(:order) { Order.create } + let!(:line_item) { order.contents.add(create(:variant), 30) } + + before { Config.track_inventory_levels = false } + + it "doesn't bother stock items status in stock location" do + expect(subject.stock_location).not_to receive(:fill_status) + subject.default_package + end + + it "still creates package with proper quantity" do + expect(subject.default_package.quantity).to eql 30 + end + end + end + end + end +end