diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 33970eb805..894146e628 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -681,7 +681,6 @@ Style/FrozenStringLiteralComment: - 'app/models/product_import/entry_validator.rb' - 'app/models/product_import/inventory_reset_strategy.rb' - 'app/models/product_import/product_importer.rb' - - 'app/models/product_import/products_reset_strategy.rb' - 'app/models/product_import/reset_absent.rb' - 'app/models/product_import/settings.rb' - 'app/models/product_import/spreadsheet_data.rb' @@ -1257,7 +1256,6 @@ Style/FrozenStringLiteralComment: - 'spec/models/producer_property_spec.rb' - 'spec/models/product_import/entry_processor_spec.rb' - 'spec/models/product_import/inventory_reset_strategy_spec.rb' - - 'spec/models/product_import/products_reset_strategy_spec.rb' - 'spec/models/product_import/reset_absent_spec.rb' - 'spec/models/product_import/settings_spec.rb' - 'spec/models/product_importer_spec.rb' diff --git a/Gemfile b/Gemfile index a07f9c26ce..e7613ec156 100644 --- a/Gemfile +++ b/Gemfile @@ -12,6 +12,7 @@ gem "activerecord-import" # Patched version. See http://rubysec.com/advisories/CVE-2015-5312/. gem 'nokogiri', '>= 1.6.7.1' +gem "catalog", path: "./engines/catalog" gem "order_management", path: "./engines/order_management" gem 'web', path: './engines/web' diff --git a/Gemfile.lock b/Gemfile.lock index 2fb86f2dd3..292a9e3448 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -75,6 +75,11 @@ GIT activemodel (>= 3.0) railties (>= 3.0) +PATH + remote: engines/catalog + specs: + catalog (0.0.1) + PATH remote: engines/order_management specs: @@ -711,6 +716,7 @@ DEPENDENCIES bugsnag byebug (~> 9.0.0) capybara (>= 2.18.0) + catalog! coffee-rails (~> 3.2.1) combine_pdf compass-rails diff --git a/app/models/product_import/entry_processor.rb b/app/models/product_import/entry_processor.rb index df2765d932..3be6dddb31 100644 --- a/app/models/product_import/entry_processor.rb +++ b/app/models/product_import/entry_processor.rb @@ -74,7 +74,7 @@ module ProductImport if settings.importing_into_inventory? InventoryResetStrategy else - ProductsResetStrategy + Catalog::ProductImport::ProductsResetStrategy end end diff --git a/app/models/product_import/products_reset_strategy.rb b/app/models/product_import/products_reset_strategy.rb deleted file mode 100644 index 989f5a275c..0000000000 --- a/app/models/product_import/products_reset_strategy.rb +++ /dev/null @@ -1,45 +0,0 @@ -module ProductImport - class ProductsResetStrategy - def initialize(excluded_items_ids) - @excluded_items_ids = excluded_items_ids - end - - def reset(enterprise_ids) - @enterprise_ids = enterprise_ids - - return 0 if enterprise_ids.blank? - - reset_variants_on_hand(enterprise_variants_relation) - end - - private - - attr_reader :excluded_items_ids, :enterprise_ids - - def enterprise_variants_relation - relation = Spree::Variant - .joins(:product) - .where( - spree_products: { supplier_id: enterprise_ids }, - spree_variants: { is_master: false, deleted_at: nil } - ) - - return relation if excluded_items_ids.blank? - - relation.where('spree_variants.id NOT IN (?)', excluded_items_ids) - end - - def reset_variants_on_hand(variants) - updated_records_count = 0 - variants.each do |variant| - updated_records_count += 1 if reset_variant_on_hand(variant) - end - updated_records_count - end - - def reset_variant_on_hand(variant) - variant.on_hand = 0 - variant.on_hand.zero? - end - end -end diff --git a/config/routes.rb b/config/routes.rb index 65a70165e1..ae3c131ac3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -91,6 +91,7 @@ Openfoodnetwork::Application.routes.draw do # Mount engine routes mount Web::Engine, :at => '/' + mount Catalog::Engine, :at => '/' mount OrderManagement::Engine, :at => '/' # Mount Spree's routes diff --git a/engines/catalog/README.md b/engines/catalog/README.md new file mode 100644 index 0000000000..129ca0d0b6 --- /dev/null +++ b/engines/catalog/README.md @@ -0,0 +1,5 @@ +# Catalog + +This is the rails engine for the Catalog domain. + +See our wiki for [more info about domains and engines in OFN](https://github.com/openfoodfoundation/openfoodnetwork/wiki/Tech-Doc:-How-OFN-is-organized-in-Domains-using-Rails-Engines). diff --git a/engines/catalog/app/assets/javascripts/catalog/all.js b/engines/catalog/app/assets/javascripts/catalog/all.js new file mode 100644 index 0000000000..15ebed9422 --- /dev/null +++ b/engines/catalog/app/assets/javascripts/catalog/all.js @@ -0,0 +1,13 @@ +// This is a manifest file that'll be compiled into application.js, which will include all the files +// listed below. +// +// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, +// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. +// +// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the +// the compiled file. +// +// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD +// GO AFTER THE REQUIRES BELOW. +// +//= require_tree . diff --git a/engines/catalog/app/assets/javascripts/catalog/catalog.js b/engines/catalog/app/assets/javascripts/catalog/catalog.js new file mode 100644 index 0000000000..dee720facd --- /dev/null +++ b/engines/catalog/app/assets/javascripts/catalog/catalog.js @@ -0,0 +1,2 @@ +// Place all the behaviors and hooks related to the matching controller here. +// All this logic will automatically be available in application.js. diff --git a/engines/catalog/app/assets/stylesheets/catalog/all.css.scss b/engines/catalog/app/assets/stylesheets/catalog/all.css.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/engines/catalog/app/controllers/catalog/application_controller.rb b/engines/catalog/app/controllers/catalog/application_controller.rb new file mode 100644 index 0000000000..f92c5371fa --- /dev/null +++ b/engines/catalog/app/controllers/catalog/application_controller.rb @@ -0,0 +1,5 @@ +module Catalog + class ApplicationController < ActionController::Base + protect_from_forgery with: :exception + end +end diff --git a/engines/catalog/app/services/catalog/product_import/products_reset_strategy.rb b/engines/catalog/app/services/catalog/product_import/products_reset_strategy.rb new file mode 100644 index 0000000000..c4cf28cdf1 --- /dev/null +++ b/engines/catalog/app/services/catalog/product_import/products_reset_strategy.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +module Catalog + module ProductImport + class ProductsResetStrategy + def initialize(excluded_items_ids) + @excluded_items_ids = excluded_items_ids + end + + def reset(enterprise_ids) + @enterprise_ids = enterprise_ids + + return 0 if enterprise_ids.blank? + + reset_variants_on_hand(enterprise_variants_relation) + end + + private + + attr_reader :excluded_items_ids, :enterprise_ids + + def enterprise_variants_relation + relation = Spree::Variant + .joins(:product) + .where( + spree_products: { supplier_id: enterprise_ids }, + spree_variants: { is_master: false, deleted_at: nil } + ) + + return relation if excluded_items_ids.blank? + + relation.where('spree_variants.id NOT IN (?)', excluded_items_ids) + end + + def reset_variants_on_hand(variants) + updated_records_count = 0 + variants.each do |variant| + updated_records_count += 1 if reset_variant_on_hand(variant) + end + updated_records_count + end + + def reset_variant_on_hand(variant) + variant.on_hand = 0 + variant.on_hand.zero? + end + end + end +end diff --git a/engines/catalog/catalog.gemspec b/engines/catalog/catalog.gemspec new file mode 100644 index 0000000000..1dd0e4fed2 --- /dev/null +++ b/engines/catalog/catalog.gemspec @@ -0,0 +1,13 @@ +$LOAD_PATH.push File.expand_path('lib', __dir__) + +require "catalog/version" + +Gem::Specification.new do |s| + s.name = "catalog" + s.version = Catalog::VERSION + s.authors = ["developers@ofn"] + s.summary = "Catalog domain of the OFN solution." + + s.files = Dir["{app,config,db,lib}/**/*"] + ["LICENSE.txt", "Rakefile", "README.rdoc"] + s.test_files = Dir["test/**/*"] +end diff --git a/engines/catalog/config/routes.rb b/engines/catalog/config/routes.rb new file mode 100644 index 0000000000..a56f4a0b70 --- /dev/null +++ b/engines/catalog/config/routes.rb @@ -0,0 +1,2 @@ +Catalog::Engine.routes.draw do +end diff --git a/engines/catalog/lib/catalog.rb b/engines/catalog/lib/catalog.rb new file mode 100644 index 0000000000..9082a273df --- /dev/null +++ b/engines/catalog/lib/catalog.rb @@ -0,0 +1,4 @@ +require "catalog/engine" + +module Catalog +end diff --git a/engines/catalog/lib/catalog/engine.rb b/engines/catalog/lib/catalog/engine.rb new file mode 100644 index 0000000000..d3a6e33bd7 --- /dev/null +++ b/engines/catalog/lib/catalog/engine.rb @@ -0,0 +1,5 @@ +module Catalog + class Engine < ::Rails::Engine + isolate_namespace Catalog + end +end diff --git a/engines/catalog/lib/catalog/version.rb b/engines/catalog/lib/catalog/version.rb new file mode 100644 index 0000000000..288c406a2b --- /dev/null +++ b/engines/catalog/lib/catalog/version.rb @@ -0,0 +1,3 @@ +module Catalog + VERSION = "0.0.1".freeze +end diff --git a/engines/catalog/spec/services/catalog/product_import/products_reset_strategy_spec.rb b/engines/catalog/spec/services/catalog/product_import/products_reset_strategy_spec.rb new file mode 100644 index 0000000000..a2fd01d01b --- /dev/null +++ b/engines/catalog/spec/services/catalog/product_import/products_reset_strategy_spec.rb @@ -0,0 +1,127 @@ +# frozen_string_literal: true + +require 'spec_helper' + +module Catalog + module ProductImport + describe ProductsResetStrategy do + let(:products_reset) { described_class.new(excluded_items_ids) } + + describe '#reset' do + let(:supplier_ids) { enterprise.id } + let(:product) { create(:product) } + let(:enterprise) { product.supplier } + let(:variant) { product.variants.first } + + before { variant.on_hand = 2 } + + context 'when there are excluded_items_ids' do + let(:excluded_items_ids) { [variant.id] } + + context 'and supplier_ids is []' do + let(:supplier_ids) { [] } + + it 'does not reset the variant.on_hand' do + products_reset.reset(supplier_ids) + expect(variant.reload.on_hand).to eq(2) + end + end + + context 'and supplier_ids is nil' do + let(:supplier_ids) { nil } + + it 'does not reset the variant.on_hand' do + products_reset.reset(supplier_ids) + expect(variant.reload.on_hand).to eq(2) + end + end + + context 'and supplier_ids is set' do + it 'does not update the on_hand of the excluded items' do + products_reset.reset(supplier_ids) + expect(variant.reload.on_hand).to eq(2) + end + + it 'updates the on_hand of the non-excluded items' do + non_excluded_variant = create( + :variant, + product: variant.product + ) + non_excluded_variant.on_hand = 3 + products_reset.reset(supplier_ids) + expect(non_excluded_variant.reload.on_hand).to eq(0) + end + end + end + + context 'when there are no excluded_items_ids' do + let(:excluded_items_ids) { [] } + + context 'and supplier_ids is []' do + let(:supplier_ids) { [] } + + it 'does not reset the variant.on_hand' do + products_reset.reset(supplier_ids) + expect(variant.reload.on_hand).to eq(2) + end + end + + context 'and supplier_ids is nil' do + let(:supplier_ids) { nil } + + it 'does not reset the variant.on_hand' do + products_reset.reset(supplier_ids) + expect(variant.reload.on_hand).to eq(2) + end + end + + context 'and supplier_ids is not nil' do + it 'sets all on_hand to 0' do + updated_records_count = products_reset.reset(supplier_ids) + expect(variant.reload.on_hand).to eq(0) + expect(updated_records_count).to eq(1) + end + + context 'and there is an unresetable variant' do + before do + variant.stock_items = [] # this makes variant.on_hand raise an error + end + + it 'returns correct number of resetted variants' do + expect { products_reset.reset(supplier_ids) }.to raise_error RuntimeError + end + end + end + end + + context 'when excluded_items_ids is nil' do + let(:excluded_items_ids) { nil } + + context 'and supplier_ids is []' do + let(:supplier_ids) { [] } + + it 'does not reset the variant.on_hand' do + products_reset.reset(supplier_ids) + expect(variant.reload.on_hand).to eq(2) + end + end + + context 'and supplier_ids is nil' do + let(:supplier_ids) { nil } + it 'does not reset the variant.on_hand' do + products_reset.reset(supplier_ids) + expect(variant.reload.on_hand).to eq(2) + end + end + + context 'and supplier_ids is nil' do + it 'sets all on_hand to 0' do + products_reset.reset(supplier_ids) + expect(variant.reload.on_hand).to eq(0) + end + end + end + end + end + end +end diff --git a/engines/catalog/spec/spec_helper.rb b/engines/catalog/spec/spec_helper.rb new file mode 100644 index 0000000000..9cfd0bc717 --- /dev/null +++ b/engines/catalog/spec/spec_helper.rb @@ -0,0 +1,3 @@ +require "../../spec/spec_helper.rb" + +Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f } diff --git a/spec/models/product_import/entry_processor_spec.rb b/spec/models/product_import/entry_processor_spec.rb index ab854c5ec4..3f8db18fed 100644 --- a/spec/models/product_import/entry_processor_spec.rb +++ b/spec/models/product_import/entry_processor_spec.rb @@ -94,13 +94,13 @@ describe ProductImport::EntryProcessor do context 'when not importing into inventory' do let(:reset_stock_strategy) do - instance_double(ProductImport::ProductsResetStrategy) + instance_double(Catalog::ProductImport::ProductsResetStrategy) end before do allow(settings).to receive(:importing_into_inventory?) { false } - allow(ProductImport::ProductsResetStrategy) + allow(Catalog::ProductImport::ProductsResetStrategy) .to receive(:new).with([1]) { reset_stock_strategy } end diff --git a/spec/models/product_import/products_reset_strategy_spec.rb b/spec/models/product_import/products_reset_strategy_spec.rb deleted file mode 100644 index e44249e8a3..0000000000 --- a/spec/models/product_import/products_reset_strategy_spec.rb +++ /dev/null @@ -1,121 +0,0 @@ -require 'spec_helper' - -describe ProductImport::ProductsResetStrategy do - let(:products_reset) { described_class.new(excluded_items_ids) } - - describe '#reset' do - let(:supplier_ids) { enterprise.id } - let(:product) { create(:product) } - let(:enterprise) { product.supplier } - let(:variant) { product.variants.first } - - before { variant.on_hand = 2 } - - context 'when there are excluded_items_ids' do - let(:excluded_items_ids) { [variant.id] } - - context 'and supplier_ids is []' do - let(:supplier_ids) { [] } - - it 'does not reset the variant.on_hand' do - products_reset.reset(supplier_ids) - expect(variant.reload.on_hand).to eq(2) - end - end - - context 'and supplier_ids is nil' do - let(:supplier_ids) { nil } - - it 'does not reset the variant.on_hand' do - products_reset.reset(supplier_ids) - expect(variant.reload.on_hand).to eq(2) - end - end - - context 'and supplier_ids is set' do - it 'does not update the on_hand of the excluded items' do - products_reset.reset(supplier_ids) - expect(variant.reload.on_hand).to eq(2) - end - - it 'updates the on_hand of the non-excluded items' do - non_excluded_variant = create( - :variant, - product: variant.product - ) - non_excluded_variant.on_hand = 3 - products_reset.reset(supplier_ids) - expect(non_excluded_variant.reload.on_hand).to eq(0) - end - end - end - - context 'when there are no excluded_items_ids' do - let(:excluded_items_ids) { [] } - - context 'and supplier_ids is []' do - let(:supplier_ids) { [] } - - it 'does not reset the variant.on_hand' do - products_reset.reset(supplier_ids) - expect(variant.reload.on_hand).to eq(2) - end - end - - context 'and supplier_ids is nil' do - let(:supplier_ids) { nil } - - it 'does not reset the variant.on_hand' do - products_reset.reset(supplier_ids) - expect(variant.reload.on_hand).to eq(2) - end - end - - context 'and supplier_ids is not nil' do - it 'sets all on_hand to 0' do - updated_records_count = products_reset.reset(supplier_ids) - expect(variant.reload.on_hand).to eq(0) - expect(updated_records_count).to eq(1) - end - - context 'and there is an unresetable variant' do - before do - variant.stock_items = [] # this makes variant.on_hand raise an error - end - - it 'returns correct number of resetted variants' do - expect { products_reset.reset(supplier_ids) }.to raise_error RuntimeError - end - end - end - end - - context 'when excluded_items_ids is nil' do - let(:excluded_items_ids) { nil } - - context 'and supplier_ids is []' do - let(:supplier_ids) { [] } - - it 'does not reset the variant.on_hand' do - products_reset.reset(supplier_ids) - expect(variant.reload.on_hand).to eq(2) - end - end - - context 'and supplier_ids is nil' do - let(:supplier_ids) { nil } - it 'does not reset the variant.on_hand' do - products_reset.reset(supplier_ids) - expect(variant.reload.on_hand).to eq(2) - end - end - - context 'and supplier_ids is nil' do - it 'sets all on_hand to 0' do - products_reset.reset(supplier_ids) - expect(variant.reload.on_hand).to eq(0) - end - end - end - end -end diff --git a/spec/models/product_import/reset_absent_spec.rb b/spec/models/product_import/reset_absent_spec.rb index d642c67338..990f26ff15 100644 --- a/spec/models/product_import/reset_absent_spec.rb +++ b/spec/models/product_import/reset_absent_spec.rb @@ -37,7 +37,7 @@ module ProductImport ) end - let(:reset_stock_strategy) { instance_double(ProductsResetStrategy) } + let(:reset_stock_strategy) { instance_double(Catalog::ProductImport::ProductsResetStrategy) } before do allow(entry_processor)