PI inventories additions

This commit is contained in:
Matt-Yorkley
2017-03-17 19:31:19 +00:00
parent 4e97445655
commit ffbb67d480
12 changed files with 114 additions and 50 deletions

View File

@@ -53,6 +53,9 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
$scope.resetProducts()
$scope.loading = false
$timeout ->
if $scope.showLatestImport
$scope.importDateFilter = $scope.importDates[1].id
$scope.resetProducts = ->
DirtyProducts.clear()

View File

@@ -25,6 +25,7 @@ angular.module("admin.variantOverrides").controller "AdminVariantOverridesCtrl",
$scope.resetSelectFilters = ->
$scope.producerFilter = 0
$scope.importDateFilter = '0'
$scope.query = ''
$scope.resetSelectFilters()

View File

@@ -0,0 +1,12 @@
angular.module("admin.variantOverrides").filter "importDate", ($filter, variantOverrides) ->
return (products, hub_id, date) ->
return [] if !hub_id
return $filter('filter')(products, (product) ->
return true if date == 0 or date == undefined or date == '0' or date == ''
for variant in product.variants
for vo in variantOverrides
if vo.variant_id == variant.id and vo.import_date == date
return true
false
, true)

View File

@@ -1 +1 @@
angular.module("admin.variantOverrides", ["admin.indexUtils", "admin.utils", "admin.dropdown", "admin.inventoryItems", 'ngTagsInput'])
angular.module("admin.variantOverrides", ["ofn.admin", "admin.indexUtils", "admin.utils", "admin.dropdown", "admin.inventoryItems", 'ngTagsInput'])

View File

@@ -3,6 +3,7 @@ require 'open_food_network/spree_api_key_loader'
module Admin
class VariantOverridesController < ResourceController
include OpenFoodNetwork::SpreeApiKeyLoader
include EnterprisesHelper
prepend_before_filter :load_data
before_filter :load_collection, only: [:bulk_update]
@@ -55,6 +56,10 @@ module Admin
variant_override_enterprises_per_hub
@inventory_items = InventoryItem.where(enterprise_id: @hubs)
import_dates = [{id: '0', name: 'All'}]
inventory_import_dates.map {|i| import_dates.push({id: i, name: i.to_formatted_s(:long)}) }
@import_dates = import_dates.to_json
end
def load_collection

View File

@@ -5,6 +5,7 @@ Spree::Admin::ProductsController.class_eval do
include OpenFoodNetwork::SpreeApiKeyLoader
include OrderCyclesHelper
include EnterprisesHelper
before_filter :latest_import, only: [:bulk_edit]
before_filter :load_form_data, :only => [:bulk_edit, :new, :create, :edit, :update]
before_filter :load_spree_api_key, :only => [:bulk_edit, :variant_overrides]
before_filter :strip_new_properties, only: [:create, :update]
@@ -93,6 +94,10 @@ Spree::Admin::ProductsController.class_eval do
private
def latest_import
@show_latest_import = params[:latest_import] || false
end
def load_form_data
@producers = OpenFoodNetwork::Permissions.new(spree_current_user).managed_product_enterprises.is_primary_producer.by_name
@taxons = Spree::Taxon.order(:name)

View File

@@ -53,7 +53,7 @@ class ProductImporter
end
def persisted?
false #ActiveModel, not ActiveRecord
false # ActiveModel
end
def has_entries?
@@ -188,7 +188,7 @@ class ProductImporter
rows.each_with_index do |row, i|
row_data = Hash[[headers, row].transpose]
entry = SpreadsheetEntry.new(row_data)
entry.line_number = i+2
entry.line_number = i + 2
@entries.push entry
end
@entries
@@ -238,12 +238,7 @@ class ProductImporter
def create_inventory_item(entry, existing_variant)
existing_variant_override = VariantOverride.where(variant_id: existing_variant.id, hub_id: entry.supplier_id).first
if existing_variant_override
variant_override = existing_variant_override
else
variant_override = VariantOverride.new(variant_id: existing_variant.id, hub_id: entry.supplier_id)
end
variant_override = existing_variant_override || VariantOverride.new(variant_id: existing_variant.id, hub_id: entry.supplier_id)
variant_override.assign_attributes(count_on_hand: entry.on_hand, import_date: @import_time)
check_on_hand_nil(entry, variant_override)
variant_override.assign_attributes(entry.attributes.slice('price', 'on_demand'))
@@ -260,7 +255,7 @@ class ProductImporter
end
def mark_as_inventory_item(entry, variant_override)
if variant_override.id?
if variant_override.id
entry.is_a_valid('existing_inventory_item')
entry.product_object = variant_override
updates_count_per_supplier(entry.supplier_id) unless entry.has_errors?
@@ -279,7 +274,8 @@ class ProductImporter
where('variant_overrides.hub_id IN (?)', supplier_id).
count
else
products_count = Spree::Variant.joins(:product).
products_count = Spree::Variant.
joins(:product).
where('spree_products.supplier_id IN (?)
AND spree_variants.is_master = false
AND spree_variants.deleted_at IS NULL', supplier_id).
@@ -377,7 +373,7 @@ class ProductImporter
@entries.each do |entry|
supplier_name = entry.supplier
supplier_id = @suppliers_index[supplier_name] ||
Enterprise.find_by_name(supplier_name, :select => 'id, name').try(:id)
Enterprise.find_by_name(supplier_name, select: 'id, name').try(:id)
@suppliers_index[supplier_name] = supplier_id
end
@suppliers_index
@@ -388,7 +384,7 @@ class ProductImporter
@entries.each do |entry|
producer_name = entry.producer
producer_id = @producers_index[producer_name] ||
Enterprise.find_by_name(producer_name, :select => 'id, name').try(:id)
Enterprise.find_by_name(producer_name, select: 'id, name').try(:id)
@producers_index[producer_name] = producer_id
end
@producers_index
@@ -437,6 +433,7 @@ class ProductImporter
product = Spree::Product.new()
product.assign_attributes(entry.attributes.except('id'))
assign_defaults(product, entry)
if product.save
ensure_variant_updated(product, entry)
@products_created += 1
@@ -473,6 +470,7 @@ class ProductImporter
new_item = entry.product_object
assign_defaults(new_item, entry)
new_item.import_date = @import_time
if new_item.valid? and new_item.save
display_in_inventory(new_item, true)
@inventory_created += 1
@@ -486,6 +484,7 @@ class ProductImporter
existing_item = entry.product_object
assign_defaults(existing_item, entry)
existing_item.import_date = @import_time
if existing_item.valid? and existing_item.save
display_in_inventory(existing_item)
@inventory_updated += 1
@@ -499,6 +498,7 @@ class ProductImporter
new_variant = entry.product_object
assign_defaults(new_variant, entry)
new_variant.import_date = @import_time
if new_variant.valid? and new_variant.save
@variants_created += 1
@updated_ids.push new_variant.id
@@ -511,6 +511,7 @@ class ProductImporter
variant = entry.product_object
assign_defaults(variant, entry)
variant.import_date = @import_time
if variant.valid? and variant.save
@variants_updated += 1
@updated_ids.push variant.id
@@ -584,7 +585,10 @@ class ProductImporter
# Otherwise, if a variant exists with matching display_name and unit_value, update it
match.variants.each do |existing_variant|
if existing_variant.display_name == entry.display_name and existing_variant.unit_value == Float(entry.unit_value)
if existing_variant.display_name == entry.display_name \
and existing_variant.unit_value == Float(entry.unit_value) \
and existing_variant.deleted_at == nil
mark_as_existing_variant(entry, existing_variant)
return
end
@@ -597,6 +601,7 @@ class ProductImporter
def mark_as_new_product(entry)
new_product = Spree::Product.new()
new_product.assign_attributes(entry.attributes.except('id'))
if new_product.valid?
entry.is_a_valid 'new_product' unless entry.has_errors?
else
@@ -607,6 +612,7 @@ class ProductImporter
def mark_as_existing_variant(entry, existing_variant)
existing_variant.assign_attributes(entry.attributes.except('id', 'product_id'))
check_on_hand_nil(entry, existing_variant)
if existing_variant.valid?
entry.product_object = existing_variant
entry.is_a_valid 'existing_variant' unless entry.has_errors?
@@ -620,6 +626,7 @@ class ProductImporter
new_variant = Spree::Variant.new(entry.attributes.except('id', 'product_id'))
new_variant.product_id = product_id
check_on_hand_nil(entry, new_variant)
if new_variant.valid?
entry.product_object = new_variant
entry.is_a_valid 'new_variant' unless entry.has_errors?
@@ -629,7 +636,8 @@ class ProductImporter
end
def updates_count_per_supplier(supplier_id)
if @reset_counts[supplier_id] and @reset_counts[supplier_id][:updates_count]
if @reset_counts[supplier_id] \
and @reset_counts[supplier_id][:updates_count]
@reset_counts[supplier_id][:updates_count] += 1
else
@reset_counts[supplier_id] = {updates_count: 1}
@@ -637,17 +645,17 @@ class ProductImporter
end
def check_on_hand_nil(entry, object)
if entry.on_hand.blank?
object.on_hand = 0 if object.respond_to?(:on_hand)
object.count_on_hand = 0 if object.respond_to?(:count_on_hand)
entry.on_hand_nil = true
end
return unless entry.on_hand.blank?
object.on_hand = 0 if object.respond_to?(:on_hand)
object.count_on_hand = 0 if object.respond_to?(:count_on_hand)
entry.on_hand_nil = true
end
def delete_uploaded_file
# Only delete if file is in '/tmp/product_import' directory
if @file.path == Rails.root.join('tmp', 'product_import').to_s
File.delete(@file)
end
return unless @file.path == Rails.root.join('tmp', 'product_import').to_s
File.delete(@file)
end
end

View File

@@ -46,10 +46,18 @@
- if @importer.errors.count == 0
%p All #{@importer.total_saved_count} items saved successfully
- else
%p #{@importer.total_saved_count} items saved successfully
%br
%h5 Save errors
- @importer.errors.full_messages.each do |error|
%p.save-error
&nbsp;-&nbsp; #{error}
%br
- if @importer.total_saved_count > 0
- if @import_into == 'inventories'
%a.button{href: main_app.admin_inventory_path} View Inventory
- else
%a.button{href: bulk_edit_admin_products_path + '?latest_import=true'} View Products
%a.button{href: main_app.admin_product_import_path} Back

View File

@@ -1,17 +1,22 @@
.filters.sixteen.columns.alpha.omega
.filter.four.columns.alpha
%label{ :for => 'query', ng: {class: '{disabled: !hub_id}'} }=t('admin.quick_search')
%label{for: 'query', ng: {class: '{disabled: !hub_id}'} }=t('admin.quick_search')
%br
%input.fullwidth{ :type => "text", :id => 'query', ng: { model: 'query', disabled: '!hub_id'} }
.two.columns &nbsp;
.filter_select.four.columns
%label{ :for => 'hub_id', ng: { bind: "hub_id ? '#{t('admin.shop')}' : '#{t('admin.variant_overrides.index.select_a_shop')}'" } }
%input.fullwidth{type: "text", id: 'query', ng: {model: 'query', disabled: '!hub_id'} }
.one.columns &nbsp;
.filter_select.three.columns
%label{for: 'hub_id', ng: {bind: "hub_id ? '#{t('admin.shop')}' : '#{t('admin.variant_overrides.index.select_a_shop')}'" } }
%br
%select.select2.fullwidth#hub_id{ 'ng-model' => 'hub_id', name: 'hub_id', ng: { options: 'hub.id as hub.name for (id, hub) in hubs' } }
.filter_select.four.columns
%label{ :for => 'producer_filter', ng: {class: '{disabled: !hub_id}'} }=t('admin.producer')
%select.select2.fullwidth#hub_id{name: 'hub_id', ng: {model: 'hub_id', options: 'hub.id as hub.name for (id, hub) in hubs' } }
.filter_select.three.columns
%label{for: 'producer_filter', ng: {class: '{disabled: !hub_id}'} }=t('admin.producer')
%br
%input.ofn-select2.fullwidth{ :id => 'producer_filter', type: 'number', data: 'producers', blank: "{id: 0, name: '#{t(:all)}'}", ng: { model: 'producerFilter', disabled: '!hub_id' } }
%input.ofn-select2.fullwidth{id: 'producer_filter', type: 'number', data: 'producers', blank: "{id: 0, name: '#{t(:all)}'}", ng: {model: 'producerFilter', disabled: '!hub_id' } }
.filter_select.three.columns
%label{ :for => 'import_date_filter', ng: {class: '{disabled: !hub_id}'} } #{t('admin.variant_overrides.index.import_date')}
%br
%select.fullwidth{id: 'import_date_filter', 'ofn-select2-min-search' => 5, ng: {model: 'importDateFilter', options: 'date.id as date.name for date in import_dates', disabled: '!hub_id', init: "import_dates = #{@import_dates}"} }
%options{value: '0', selected: 'selected'} #{t(:all)}
-# .filter_select{ :class => "three columns" }
-# %label{ :for => 'distributor_filter' }Hub
-# %br

View File

@@ -27,6 +27,6 @@
%th.tags{ ng: { show: 'columns.tags.visible' } }=t('admin.tags')
%th.visibility{ ng: { show: 'columns.visibility.visible' } }=t('admin.variant_overrides.index.hide')
%th.import_date{ ng: { show: 'columns.import_date.visible' } }=t('admin.variant_overrides.index.import_date')
%tbody{ ng: {repeat: 'product in filteredProducts = (products | hubPermissions:hubPermissions:hub_id | inventoryProducts:hub_id:views | attrFilter:{producer_id:producerFilter} | filter:query) | limitTo:productLimit' } }
%tbody{ ng: {repeat: 'product in filteredProducts = (products | hubPermissions:hubPermissions:hub_id | inventoryProducts:hub_id:views | attrFilter:{producer_id:producerFilter} | importDate:hub_id:importDateFilter | filter:query) | limitTo:productLimit' } }
= render 'admin/variant_overrides/products_product'
= render 'admin/variant_overrides/products_variants'

View File

@@ -1,23 +1,25 @@
.filters.sixteen.columns.alpha.omega
.quick_search.three.columns.alpha
%label{ :for => 'quick_filter' }
%label{ for: 'quick_filter' }
%br
%input.quick-search.fullwidth{ 'ng-model' => 'query', :name => "quick_filter", :type => 'text', 'placeholder' => t('admin.quick_search') }
%input.quick-search.fullwidth{ ng: {model: 'query'}, name: "quick_filter", type: 'text', placeholder: t('admin.quick_search') }
.one.columns &nbsp;
.filter_select.three.columns
%label{ :for => 'producer_filter' }= t 'producer'
%label{ for: 'producer_filter' }= t 'producer'
%br
%select.fullwidth{ :id => 'producer_filter', 'ofn-select2-min-search' => 5, 'ng-model' => 'producerFilter', 'ng-options' => 'producer.id as producer.name for producer in filterProducers' }
%select.fullwidth{ id: 'producer_filter', 'ofn-select2-min-search' => 5, ng: {model: 'producerFilter', options: 'producer.id as producer.name for producer in filterProducers'} }
.filter_select.three.columns
%label{ :for => 'category_filter' }= t 'category'
%label{ for: 'category_filter' }= t 'category'
%br
%select.fullwidth{ :id => 'category_filter', 'ofn-select2-min-search' => 5, 'ng-model' => 'categoryFilter', 'ng-options' => 'taxon.id as taxon.name for taxon in filterTaxons'}
%select.fullwidth{ id: 'category_filter', 'ofn-select2-min-search' => 5, ng: {model: 'categoryFilter', options: 'taxon.id as taxon.name for taxon in filterTaxons'} }
.filter_select.three.columns
%label{ :for => 'import_filter' } Import Date
%label{ for: 'import_filter' } Import Date
%br
%select.fullwidth{ :id => 'import_date_filter', 'ofn-select2-min-search' => 5, 'ng-model' => 'importDateFilter', 'ng-init' => "import_dates = #{@import_dates}", 'ng-options' => 'import.id as import.name for import in import_dates'}
%select.fullwidth{ id: 'import_date_filter', 'ofn-select2-min-search' => 5, ng: {model: 'importDateFilter', init: "importDates = #{@import_dates}; showLatestImport = #{@show_latest_import}"}}
%option{value: "{{date.id}}", ng: {repeat: "date in importDates track by date.id" }}
{{date.name}}
%div{ :class => "one column" } &nbsp;
.filter_clear.three.columns.omega
%label{ :for => 'clear_all_filters' }
%label{ for: 'clear_all_filters' }
%br
%input.fullwidth.red{ :type => 'button', :id => 'clear_all_filters', :value => t('admin.clear_filters'), 'ng-click' => "resetSelectFilters()" }

View File

@@ -31,7 +31,7 @@ feature "Product Import", js: true do
before { quick_login_as_admin }
after { File.delete('/tmp/test.csv') }
it "validates entries and saves them if they are all valid" do
it "validates entries and saves them if they are all valid and allows viewing new items in Bulk Products" do
csv_data = CSV.generate do |csv|
csv << ["name", "supplier", "category", "on_hand", "price", "unit_value", "variant_unit", "variant_unit_scale"]
csv << ["Carrots", "User Enterprise", "Vegetables", "5", "3.20", "500", "weight", "1"]
@@ -54,11 +54,19 @@ feature "Product Import", js: true do
expect(page).to have_selector '.created-count', text: '2'
expect(page).to_not have_selector '.updated-count'
carrots = Spree::Product.find_by_name('Carrots')
potatoes = Spree::Product.find_by_name('Potatoes')
potatoes.supplier.should == enterprise
potatoes.on_hand.should == 6
potatoes.price.should == 6.50
potatoes.variants.first.import_date.should be_within(1.minute).of DateTime.now
click_link 'View Products'
expect(page).to have_content 'Bulk Edit Products'
wait_until { page.find("#p_#{potatoes.id}").present? }
expect(page).to have_field "product_name", with: carrots.name
expect(page).to have_field "product_name", with: potatoes.name
end
it "displays info about invalid entries but still allows saving of valid entries" do
@@ -195,7 +203,7 @@ feature "Product Import", js: true do
carrots = Spree::Product.find_by_name('Carrots')
carrots.variants.first.import_date.should be_within(1.minute).of DateTime.now
visit 'admin/products/bulk_edit'
click_link 'View Products'
wait_until { page.find("#p_#{carrots.id}").present? }
@@ -246,7 +254,6 @@ feature "Product Import", js: true do
expect(page).to have_selector '.inv-created-count', text: '2'
expect(page).to have_selector '.inv-updated-count', text: '1'
beans_override = VariantOverride.where(variant_id: product2.variants.first.id, hub_id: enterprise2.id).first
sprouts_override = VariantOverride.where(variant_id: product3.variants.first.id, hub_id: enterprise2.id).first
cabbage_override = VariantOverride.where(variant_id: product4.variants.first.id, hub_id: enterprise2.id).first
@@ -259,6 +266,17 @@ feature "Product Import", js: true do
Float(cabbage_override.price).should == 1.50
cabbage_override.count_on_hand.should == 2001
click_link 'View Inventory'
expect(page).to have_content 'Inventory'
select enterprise2.name, from: "hub_id", visible: false
within '#variant-overrides' do
expect(page).to have_content 'Beans'
expect(page).to have_content 'Sprouts'
expect(page).to have_content 'Cabbage'
end
end
end
@@ -349,8 +367,6 @@ feature "Product Import", js: true do
expect(page).to_not have_selector '.invalid-count'
expect(page).to have_selector '.inv-create-count', text: "1"
#expect(page.body).to have_content 'you do not have permission'
click_button 'Save'
expect(page).to have_selector '.inv-created-count', text: '1'
@@ -379,8 +395,7 @@ feature "Product Import", js: true do
expect(page).to_not have_selector '.inv-create-count'
expect(page.body).to have_content 'you do not have permission'
expect(page).to_not have_selector 'input[type=submit][value="Save"]'
end
end