PI inventories UX

Minor tweaks
This commit is contained in:
Matt-Yorkley
2017-05-04 18:56:41 +01:00
parent 678a2a365d
commit 6efd167400
14 changed files with 231 additions and 129 deletions

View File

@@ -4,8 +4,6 @@ angular.module("ofn.admin").controller "ImportFormCtrl", ($scope, $http, $filter
$scope.update_counts = {}
$scope.reset_counts = {}
#$scope.import_options = {}
$scope.updates = {}
$scope.updated_total = 0
$scope.updated_ids = []
@@ -30,7 +28,10 @@ angular.module("ofn.admin").controller "ImportFormCtrl", ($scope, $http, $filter
$scope.started = false
$scope.finished = false
$scope.step = 'import'
$scope.step = 'settings'
$scope.confirmSettings = () ->
$scope.step = 'import'
$scope.viewResults = () ->
$scope.countResettable()
@@ -62,6 +63,7 @@ angular.module("ofn.admin").controller "ImportFormCtrl", ($scope, $http, $filter
i++
$scope.processImport = (start, end) ->
$scope.getSettings() if $scope.importSettings == null
$http(
url: $scope.import_url
method: 'POST'
@@ -69,7 +71,7 @@ angular.module("ofn.admin").controller "ImportFormCtrl", ($scope, $http, $filter
'start': start
'end': end
'filepath': $scope.filepath
'import_into': $scope.import_into
'settings': $scope.importSettings
).success((data, status, headers, config) ->
angular.merge($scope.entries, angular.fromJson(data['entries']))
$scope.sortUpdates(data['reset_counts'])
@@ -100,7 +102,6 @@ angular.module("ofn.admin").controller "ImportFormCtrl", ($scope, $http, $filter
'start': start
'end': end
'filepath': $scope.filepath
'import_into': $scope.import_into,
'settings': $scope.importSettings
).success((data, status, headers, config) ->
$scope.sortResults(data['results'])
@@ -137,7 +138,6 @@ angular.module("ofn.admin").controller "ImportFormCtrl", ($scope, $http, $filter
method: 'POST'
data:
'filepath': $scope.filepath
'import_into': $scope.import_into,
'settings': $scope.importSettings
'reset_absent': true,
'updated_ids': $scope.updated_ids,

View File

@@ -3,6 +3,7 @@ angular.module("ofn.admin").controller "ImportOptionsFormCtrl", ($scope, $rootSc
$scope.initForm = () ->
$scope.settings = {} if $scope.settings == undefined
$scope.settings[$scope.supplierId] = {
import_into: 'product_list'
defaults:
count_on_hand:
mode: 'overwrite_all'
@@ -15,6 +16,10 @@ angular.module("ofn.admin").controller "ImportOptionsFormCtrl", ($scope, $rootSc
available_on:
mode: 'overwrite_all'
}
$scope.import_into = 'product_list'
$scope.updateImportInto = () ->
$scope.import_into = $scope.settings[$scope.supplierId]['import_into']
$scope.$watch 'settings', (updated) ->
ProductImportService.updateSettings(updated)

View File

@@ -9,7 +9,6 @@ class Admin::ProductImportController < Spree::Admin::BaseController
@filepath = save_uploaded_file(params[:file])
@importer = ProductImporter.new(File.new(@filepath), spree_current_user, params[:settings])
@original_filename = params[:file].try(:original_filename)
@import_into = params[:settings][:import_into]
check_file_errors @importer
check_spreadsheet_has_data @importer
@@ -25,7 +24,7 @@ class Admin::ProductImportController < Spree::Admin::BaseController
# end
def process_data
@importer = ProductImporter.new(File.new(params[:filepath]), spree_current_user, {start: params[:start], end: params[:end], import_into: params[:import_into]})
@importer = ProductImporter.new(File.new(params[:filepath]), spree_current_user, {start: params[:start], end: params[:end], settings: params[:settings]})
@importer.validate_entries
@@ -33,7 +32,7 @@ class Admin::ProductImportController < Spree::Admin::BaseController
end
def save_data
@importer = ProductImporter.new(File.new(params[:filepath]), spree_current_user, {start: params[:start], end: params[:end], import_into: params[:import_into], settings: params[:settings]})
@importer = ProductImporter.new(File.new(params[:filepath]), spree_current_user, {start: params[:start], end: params[:end], settings: params[:settings]})
@importer.save_entries

View File

@@ -26,7 +26,7 @@ class ProductImporter
@inventory_updated = 0
@import_time = DateTime.now
@import_settings = import_settings
@import_settings = import_settings || {}
@current_user = current_user
@editable_enterprises = {}
@@ -36,6 +36,7 @@ class ProductImporter
@supplier_products = {}
@reset_counts = {}
@updated_ids = []
@products_reset_count = 0
init_product_importer if @sheet
else
@@ -115,7 +116,7 @@ class ProductImporter
end
def products_reset_count
@products_reset_count || 0
@products_reset_count
end
def total_saved_count
@@ -160,8 +161,11 @@ class ProductImporter
def validate_entries
@entries.each do |entry|
supplier_validation(entry)
unit_fields_validation(entry)
if importing_into_inventory?
next unless entry.supplier_id.present?
if import_into_inventory?(entry)
producer_validation(entry)
inventory_validation(entry)
else
@@ -172,6 +176,10 @@ class ProductImporter
end
end
def import_into_inventory?(entry)
entry.supplier_id and @import_settings[:settings][entry.supplier_id.to_s]['import_into'] == 'inventories'
end
def save_entries
validate_entries
save_all_valid
@@ -187,7 +195,7 @@ class ProductImporter
def init_product_importer
init_permissions
if @import_settings.has_key?(:start) and @import_settings.has_key?(:end)
if @import_settings and @import_settings.has_key?(:start) and @import_settings.has_key?(:end)
build_entries_in_range
else
build_entries
@@ -195,7 +203,7 @@ class ProductImporter
build_categories_index
build_suppliers_index
build_tax_and_shipping_indexes
build_producers_index if importing_into_inventory?
build_producers_index ###if importing_into_inventory? #TODO: check this is still working ok
#validate_all
count_existing_items unless @import_settings.has_key?(:start)
end
@@ -243,7 +251,7 @@ class ProductImporter
line_number = i + 1
row = @sheet.row(line_number)
row_data = Hash[[headers, row].transpose]
entry = SpreadsheetEntry.new(row_data, importing_into_inventory?)
entry = SpreadsheetEntry.new(row_data)
entry.line_number = line_number
@entries.push entry
return if @sheet.last_row == line_number # TODO: test
@@ -253,7 +261,7 @@ class ProductImporter
def build_entries
rows.each_with_index do |row, i|
row_data = Hash[[headers, row].transpose]
entry = SpreadsheetEntry.new(row_data, importing_into_inventory?)
entry = SpreadsheetEntry.new(row_data)
entry.line_number = i + 2
@entries.push entry
end
@@ -263,8 +271,11 @@ class ProductImporter
def validate_all
@entries.each do |entry|
supplier_validation(entry)
unit_fields_validation(entry)
if importing_into_inventory?
next unless entry.supplier_id.present?
if import_into_inventory?(entry)
producer_validation(entry)
inventory_validation(entry)
else
@@ -278,9 +289,9 @@ class ProductImporter
delete_uploaded_file if item_count.zero? or !has_valid_entries?
end
def importing_into_inventory?
@import_settings[:import_into] == 'inventories'
end
# def importing_into_inventory?
# @import_settings[:import_into] == 'inventories'
# end
def inventory_validation(entry)
# Find product with matching supplier and name
@@ -340,7 +351,7 @@ class ProductImporter
@suppliers_index.each do |supplier_name, supplier_id|
next unless supplier_id and permission_by_id?(supplier_id)
if importing_into_inventory?
if import_into_inventory_by_supplier?(supplier_id)
products_count = VariantOverride.
where('variant_overrides.hub_id IN (?)', supplier_id).
count
@@ -358,6 +369,10 @@ class ProductImporter
end
end
def import_into_inventory_by_supplier?(supplier_id)
@import_settings[:settings] and @import_settings[:settings][supplier_id.to_s] and @import_settings[:settings][supplier_id.to_s]['import_into'] == 'inventories'
end
def supplier_validation(entry)
supplier_name = entry.supplier
@@ -471,6 +486,7 @@ class ProductImporter
def build_producers_index
@producers_index = {}
@entries.each do |entry|
next unless entry.producer
producer_name = entry.producer
producer_id = @producers_index[producer_name] ||
Enterprise.find_by_name(producer_name, select: 'id, name').try(:id)
@@ -499,7 +515,7 @@ class ProductImporter
def save_all_valid
@entries.each do |entry|
if importing_into_inventory?
if import_into_inventory?(entry)
save_new_inventory_item entry if entry.is_a_valid? 'new_inventory_item'
save_existing_inventory_item entry if entry.is_a_valid? 'existing_inventory_item'
else
@@ -617,28 +633,30 @@ class ProductImporter
end
def reset_absent_items
return if total_saved_count.zero? or @updated_ids.empty? or !@import_settings.has_key?('settings')
return if total_saved_count.zero? or @updated_ids.empty? or !@import_settings.has_key?(:settings)
suppliers_to_reset_products = []
suppliers_to_reset_inventories = []
enterprises_to_reset = []
@import_settings['settings'].each do |enterprise_id, settings|
enterprises_to_reset.push enterprise_id if settings['reset_all_absent'] and permission_by_id?(enterprise_id)
@import_settings[:settings].each do |enterprise_id, settings|
suppliers_to_reset_products.push enterprise_id if settings['reset_all_absent'] and permission_by_id?(enterprise_id) and !import_into_inventory_by_supplier?(enterprise_id)
suppliers_to_reset_inventories.push enterprise_id if settings['reset_all_absent'] and permission_by_id?(enterprise_id) and import_into_inventory_by_supplier?(enterprise_id)
end
return if enterprises_to_reset.empty?
# For selected enterprises; set stock to zero for all products/inventory
# items that were not present in the uploaded spreadsheet
if importing_into_inventory?
@products_reset_count = VariantOverride.
unless suppliers_to_reset_inventories.empty?
@products_reset_count += VariantOverride.
where('variant_overrides.hub_id IN (?)
AND variant_overrides.id NOT IN (?)', enterprises_to_reset, @updated_ids).
AND variant_overrides.id NOT IN (?)', suppliers_to_reset_inventories, @updated_ids).
update_all(count_on_hand: 0)
else
@products_reset_count = Spree::Variant.joins(:product).
end
unless suppliers_to_reset_products.empty?
@products_reset_count += Spree::Variant.joins(:product).
where('spree_products.supplier_id IN (?)
AND spree_variants.id NOT IN (?)
AND spree_variants.is_master = false
AND spree_variants.deleted_at IS NULL', enterprises_to_reset, @updated_ids).
AND spree_variants.deleted_at IS NULL', suppliers_to_reset_products, @updated_ids).
update_all(count_on_hand: 0)
end
end
@@ -669,6 +687,31 @@ class ProductImporter
variant.save
end
def unit_fields_validation(entry)
unit_types = ['g', 'kg', 't', 'ml', 'l', 'kl', '']
# unit must be present and not nil
unless entry.units and entry.units.present?
#self.errors.add('units', "can't be blank")
mark_as_invalid(entry, attribute: 'units', error: I18n.t('admin.product_import.model.blank'))
end
return if import_into_inventory?(entry)
# unit_type must be valid type
if entry.unit_type and entry.unit_type.present?
unit_type = entry.unit_type.to_s.strip.downcase
#self.errors.add('unit_type', "incorrect value") unless unit_types.include?(unit_type)
mark_as_invalid(entry, attribute: 'unit_type', error: I18n.t('admin.product_import.model.incorrect_value')) unless unit_types.include?(unit_type)
end
# variant_unit_name must be present if unit_type not present
if !entry.unit_type or (entry.unit_type and entry.unit_type.blank?)
#self.errors.add('variant_unit_name', "can't be blank if unit_type is blank") unless attrs.has_key? 'variant_unit_name' and attrs['variant_unit_name'].present?
mark_as_invalid(entry, attribute: 'variant_unit_name', error: I18n.t('admin.product_import.model.conditional_blank')) unless entry.variant_unit_name and entry.variant_unit_name.present?
end
end
def product_validation(entry)
# Find product with matching supplier and name
match = Spree::Product.where(supplier_id: entry.supplier_id, name: entry.name, deleted_at: nil).first

View File

@@ -14,12 +14,12 @@ class SpreadsheetEntry
:display_as, :category, :primary_taxon_id, :price, :on_hand, :count_on_hand, :on_demand,
:tax_category_id, :shipping_category_id, :description, :import_date
def initialize(attrs, is_inventory=false)
def initialize(attrs)
#@product_validations = {}
@validates_as = ''
validate_custom_unit_fields(attrs, is_inventory)
convert_custom_unit_fields(attrs, is_inventory)
#validate_custom_unit_fields(attrs, is_inventory)
convert_custom_unit_fields(attrs)
attrs.each do |k, v|
if self.respond_to?("#{k}=")
@@ -42,7 +42,7 @@ class SpreadsheetEntry
}
end
def convert_custom_unit_fields(attrs, is_inventory)
def convert_custom_unit_fields(attrs)
# unit unit_type variant_unit_name -> unit_value variant_unit_scale variant_unit
# 250 ml nil .... 0.25 0.001 volume
@@ -54,7 +54,7 @@ class SpreadsheetEntry
attrs['variant_unit_scale'] = nil
attrs['unit_value'] = nil
if is_inventory and attrs.has_key?('units') and attrs['units'].present?
if attrs.has_key?('units') and attrs['units'].present?
attrs['unscaled_units'] = attrs['units']
end
@@ -126,30 +126,8 @@ class SpreadsheetEntry
unit_scales.has_key? unit_type
end
def validate_custom_unit_fields(attrs, is_inventory)
unit_types = ['g', 'kg', 't', 'ml', 'l', 'kl', '']
# unit must be present and not nil
unless attrs.has_key? 'units' and attrs['units'].present?
self.errors.add('units', "can't be blank")
end
return if is_inventory
# unit_type must be valid type
if attrs.has_key? 'unit_type' and attrs['unit_type'].present?
unit_type = attrs['unit_type'].to_s.strip.downcase
self.errors.add('unit_type', "incorrect value") unless unit_types.include?(unit_type)
end
# variant_unit_name must be present if unit_type not present
if !attrs.has_key? 'unit_type' or ( attrs.has_key? 'unit_type' and attrs['unit_type'].blank? )
self.errors.add('variant_unit_name', "can't be blank if unit_type is blank") unless attrs.has_key? 'variant_unit_name' and attrs['variant_unit_name'].present?
end
end
def non_display_attributes
['id', 'product_id', 'unscaled_units', 'variant_id', 'supplier_id', 'primary_taxon', 'primary_taxon_id', 'category_id', 'shipping_category_id', 'tax_category_id']
['id', 'product_id', 'unscaled_units', 'variant_id', 'supplier_id', 'primary_taxon', 'primary_taxon_id', 'category_id', 'shipping_category_id', 'tax_category_id', 'variant_unit_scale', 'variant_unit', 'unit_value']
end
def non_product_attributes

View File

@@ -12,8 +12,7 @@
%div.header-description
= name
%div.panel-content{ng: {hide: '!active'}}
= render 'product_options_form', supplier_id: supplier_id, name: name if @import_into == 'product_list'
= render 'inventory_options_form', supplier_id: supplier_id, name: name if @import_into == 'inventories'
= render 'options_form', supplier_id: supplier_id, name: name
- elsif name and supplier_id
%div.panel-section.import-settings{ng: {controller: 'DropdownPanelsCtrl'}}
%div.panel-header

View File

@@ -1,19 +0,0 @@
%table.import-settings{ng: {controller: 'ImportOptionsFormCtrl', init: "supplierId = #{supplier_id}; initForm()"}}
%tr
%td.description
#{t('admin.product_import.import.reset_absent?')}
%td
= check_box_tag "settings[#{supplier_id}][reset_all_absent]", 1, false, 'ng-model' => "settings[#{supplier_id}]['reset_all_absent']", 'ng-change' => "toggleResetAbsent('#{supplier_id}')"
%td
%td
%td
%tr
%td.description
#{t('admin.product_import.import.default_stock')}
%td
= check_box_tag "settings[#{supplier_id}][defaults][count_on_hand][active]", 1, false, 'ng-model' => "settings[#{supplier_id}]['defaults']['count_on_hand']['active']"
%td
%td
= select_tag "settings[#{supplier_id}][defaults][count_on_hand][mode]", options_for_select({"#{t('admin.product_import.import.overwrite_all')}" => :overwrite_all, "#{t('admin.product_import.import.overwrite_empty')}" => :overwrite_empty}), {class: 'select2 fullwidth select2-no-search', 'ng-model' => "settings[#{supplier_id}]['defaults']['count_on_hand']['mode']", 'ng-disabled' => "!settings[#{supplier_id}]['defaults']['count_on_hand']['active']"}
%td
= number_field_tag "settings[#{supplier_id}][defaults][count_on_hand][value]", 0, 'ng-disabled' => "!settings[#{supplier_id}]['defaults']['count_on_hand']['active']", 'ng-model' => "settings[#{supplier_id}]['defaults']['count_on_hand']['value']"

View File

@@ -1,12 +1,23 @@
%table.import-settings{ng: {controller: 'ImportOptionsFormCtrl', init: "supplierId = #{supplier_id}; initForm()"}}
%tr
%td.description
#{t('admin.product_import.import.reset_absent?')}
%td
= check_box_tag "settings[#{supplier_id}][reset_all_absent]", 1, false, :'ng-model' => "settings[#{supplier_id}]['reset_all_absent']", :'ng-change' => "toggleResetAbsent('#{supplier_id}')"
Import Into:
%td
%td
%tr
= select_tag "settings[#{supplier_id}][import_into]", options_for_select({"Product List" => :product_list, "Inventories" => :inventories}), {class: 'select2 fullwidth select2-no-search', 'ng-model' => "settings[#{supplier_id}]['import_into']", 'ng-change' => "updateImportInto()"}
%td
%tr{ng: {show: 'import_into == "inventories"'}}
%td.description
#{t('admin.product_import.import.default_stock')}
%td
= check_box_tag "settings[#{supplier_id}][defaults][count_on_hand][active]", 1, false, 'ng-model' => "settings[#{supplier_id}]['defaults']['count_on_hand']['active']"
%td
= select_tag "settings[#{supplier_id}][defaults][count_on_hand][mode]", options_for_select({"#{t('admin.product_import.import.overwrite_all')}" => :overwrite_all, "#{t('admin.product_import.import.overwrite_empty')}" => :overwrite_empty}), {class: 'select2 fullwidth select2-no-search', 'ng-model' => "settings[#{supplier_id}]['defaults']['count_on_hand']['mode']", 'ng-disabled' => "!settings[#{supplier_id}]['defaults']['count_on_hand']['active']"}
%td
= number_field_tag "settings[#{supplier_id}][defaults][count_on_hand][value]", 0, 'ng-disabled' => "!settings[#{supplier_id}]['defaults']['count_on_hand']['active']", 'ng-model' => "settings[#{supplier_id}]['defaults']['count_on_hand']['value']"
%tr{ng: {show: 'import_into == "product_list"'}}
%td.description
#{t('admin.product_import.import.default_stock')}
%td
@@ -15,7 +26,7 @@
= select_tag "settings[#{supplier_id}][defaults][on_hand][mode]", options_for_select({"#{t('admin.product_import.import.overwrite_all')}" => :overwrite_all, "#{t('admin.product_import.import.overwrite_empty')}" => :overwrite_empty}), {class: 'select2 fullwidth select2-no-search', 'ng-model' => "settings[#{supplier_id}]['defaults']['on_hand']['mode']", 'ng-disabled' => "!settings[#{supplier_id}]['defaults']['on_hand']['active']"}
%td
= number_field_tag "settings[#{supplier_id}][defaults][on_hand][value]", 0, 'ng-model' => "settings[#{supplier_id}]['defaults']['on_hand']['value']", 'ng-disabled' => "!settings[#{supplier_id}]['defaults']['on_hand']['active']"
%tr
%tr{ng: {show: 'import_into == "product_list"'}}
%td.description
#{t('admin.product_import.import.default_tax_cat')}
%td
@@ -24,7 +35,7 @@
= select_tag "settings[#{supplier_id}][defaults][tax_category_id][mode]", options_for_select({"#{t('admin.product_import.import.overwrite_all')}" => :overwrite_all, "#{t('admin.product_import.import.overwrite_empty')}" => :overwrite_empty}), {class: 'select2 fullwidth select2-no-search', 'ng-model' => "settings[#{supplier_id}]['defaults']['tax_category_id']['mode']", 'ng-disabled' => "!settings[#{supplier_id}]['defaults']['tax_category_id']['active']"}
%td
= select_tag "settings[#{supplier_id}][defaults][tax_category_id][value]", options_for_select(@tax_categories.map {|tc| [tc.name, tc.id]}), {prompt: 'None', class: 'select2 fullwidth select2-no-search', 'ng-model' => "settings[#{supplier_id}]['defaults']['tax_category_id']['value']", 'ng-disabled' => "!settings[#{supplier_id}]['defaults']['tax_category_id']['active']"}
%tr
%tr{ng: {show: 'import_into == "product_list"'}}
%td.description
#{t('admin.product_import.import.default_shipping_cat')}
%td
@@ -33,7 +44,7 @@
= select_tag "settings[#{supplier_id}][defaults][shipping_category_id][mode]", options_for_select({"#{t('admin.product_import.import.overwrite_all')}" => :overwrite_all, "#{t('admin.product_import.import.overwrite_empty')}" => :overwrite_empty}), {class: 'select2 fullwidth select2-no-search', 'ng-model' => "settings[#{supplier_id}]['defaults']['shipping_category_id']['mode']", 'ng-disabled' => "!settings[#{supplier_id}]['defaults']['shipping_category_id']['active']"}
%td
= select_tag "settings[#{supplier_id}][defaults][shipping_category_id][value]", options_for_select(@shipping_categories.map {|sc| [sc.name, sc.id]}), {prompt: 'None', class: 'select2 fullwidth select2-no-search', 'ng-model' => "settings[#{supplier_id}]['defaults']['shipping_category_id']['value']", 'ng-disabled' => "!settings[#{supplier_id}]['defaults']['shipping_category_id']['active']"}
%tr
%tr{ng: {show: 'import_into == "product_list"'}}
%td.description
#{t('admin.product_import.import.default_available_date')}
%td
@@ -42,3 +53,11 @@
= select_tag "settings[#{supplier_id}][defaults][available_on][mode]", options_for_select({"#{t('admin.product_import.import.overwrite_all')}" => :overwrite_all, "#{t('admin.product_import.import.overwrite_empty')}" => :overwrite_empty}), {class: 'select2 fullwidth select2-no-search', 'ng-model' => "settings[#{supplier_id}]['defaults']['available_on']['mode']", 'ng-disabled' => "!settings[#{supplier_id}]['defaults']['available_on']['active']"}
%td
= text_field_tag "settings[#{supplier_id}][defaults][available_on][value]", nil, {class: 'datepicker', placeholder: 'Today', 'ng-model' => "settings[#{supplier_id}]['defaults']['available_on']['value']", 'ng-disabled' => "!settings[#{supplier_id}]['defaults']['available_on']['active']"}
%tr
%td.description
#{t('admin.product_import.import.reset_absent?')}
%td
= check_box_tag "settings[#{supplier_id}][reset_all_absent]", 1, false, :'ng-model' => "settings[#{supplier_id}]['reset_all_absent']", :'ng-change' => "toggleResetAbsent('#{supplier_id}')"
%td
%td

View File

@@ -52,9 +52,8 @@
%br
%div{ng: {show: 'updated_total > 0'}}
- if @import_into == 'inventories'
%a.button.view{href: main_app.admin_inventory_path} #{t('admin.product_import.save.view_inventory')}
- else
%a.button.view{href: bulk_edit_admin_products_path + '?latest_import=true'} #{t('admin.product_import.save.view_products')}
%a.button.view{href: main_app.admin_inventory_path, ng: {show: 'updates.inventory_created > 0 || updates.inventory_updated > 0'}} #{t('admin.product_import.save.view_inventory')}
%a.button.view{href: bulk_edit_admin_products_path + '?latest_import=true', ng: {show: 'updates.products_created > 0 || updates.products_updated > 0'}} #{t('admin.product_import.save.view_products')}
%a.button{href: main_app.admin_product_import_path} #{t('admin.back')}

View File

@@ -8,10 +8,4 @@
= file_field_tag :file
%br
%br
%label #{t('admin.product_import.index.import_into')}
%br
= select_tag "settings[import_into]", options_for_select({"#{t('admin.product_import.index.product_list')}" => :product_list, "#{t('admin.product_import.index.inventories')}" => :inventories}), {class: 'select2 select2-no-search'}
%br
%br
%br
= submit_tag "#{t('admin.product_import.index.upload')}"

View File

@@ -10,22 +10,27 @@
%p #{t('admin.product_import.import.none_to_save')}
%br
- else
.progress-interface{ng: {show: 'step == "import"'}}
%span.filename
#{@original_filename}
%span.percentage
({{percentage}})
.progress-bar
%span.progress-track{class: 'ng-binding', style: "width:{{percentage}}"}
%button.start_import{ng: {click: 'start()', disabled: 'started', init: "item_count = #{@importer.item_count}; import_url = '#{main_app.admin_product_import_process_async_path}'; filepath = '#{@filepath}'; import_into = '#{@import_into}'"}}
#{t('admin.product_import.index.import')}
%button.review{ng: {click: 'viewResults()', disabled: '!finished'}}
#{t('admin.product_import.import.review')}
.settings-section{ng: {show: 'step == "settings"'}}
= render 'import_options' if @importer.table_headings
%br
%a.button{href: '', ng: {click: 'confirmSettings()'}}
#{t('admin.product_import.import.proceed')}
%a.button{href: main_app.admin_product_import_path} #{t('admin.cancel')}
.progress-interface{ng: {show: 'step == "import"'}}
%span.filename
#{@original_filename}
%span.percentage
({{percentage}})
.progress-bar
%span.progress-track{class: 'ng-binding', style: "width:{{percentage}}"}
%button.start_import{ng: {click: 'start()', disabled: 'started', init: "item_count = #{@importer.item_count}; import_url = '#{main_app.admin_product_import_process_async_path}'; filepath = '#{@filepath}'; import_into = '#{@import_into}'"}}
#{t('admin.product_import.index.import')}
%button.review{ng: {click: 'viewResults()', disabled: '!finished'}}
#{t('admin.product_import.import.review')}
= form_tag false, {class: 'product-import', name: 'importForm', 'ng-show' => 'step == "results"'} do
= render 'import_options' if @importer.table_headings
= render 'import_review' if @importer.table_headings
%div{ng: {controller: 'ImportFeedbackCtrl', show: 'count((entries | entriesFilterValid:"valid")) > 0'}}

View File

@@ -486,6 +486,8 @@ en:
model:
no_file: "error: no file uploaded"
could_not_process: "could not process file: invalid filetype"
incorrect_value: incorrect value
conditional_blank: can't be blank if unit_type is blank
no_product: did not match any products in the database
not_found: not found in database
blank: can't be blank

View File

@@ -45,9 +45,12 @@ feature "Product Import", js: true do
attach_file 'file', '/tmp/test.csv'
click_button 'Upload'
click_link 'Proceed'
expect(page).to have_selector 'button.start_import'
expect(page).to have_selector "button.review[disabled='disabled']"
sleep 0.5
click_button 'Import'
wait_until { page.find("button.review:not([disabled='disabled'])").present? }
click_button 'Review'
@@ -102,6 +105,9 @@ feature "Product Import", js: true do
attach_file 'file', '/tmp/test.csv'
click_button 'Upload'
click_link 'Proceed'
sleep 0.5
click_button 'Import'
wait_until { page.find("button.review:not([disabled='disabled'])").present? }
click_button 'Review'
@@ -128,6 +134,9 @@ feature "Product Import", js: true do
attach_file 'file', '/tmp/test.csv'
click_button 'Upload'
click_link 'Proceed'
sleep 0.5
click_button 'Import'
wait_until { page.find("button.review:not([disabled='disabled'])").present? }
click_button 'Review'
@@ -177,11 +186,17 @@ feature "Product Import", js: true do
File.write('/tmp/test.csv', csv_data)
visit main_app.admin_product_import_path
attach_file 'file', '/tmp/test.csv'
select 'Inventories', from: "settings_import_into", visible: false
click_button 'Upload'
within 'div.import-settings' do
find('div.header-description').click # Import settings tab
select 'Inventories', from: "settings_#{enterprise2.id.to_s}_import_into", visible: false
end
click_link 'Proceed'
sleep 0.5
click_button 'Import'
wait_until { page.find("button.review:not([disabled='disabled'])").present? }
click_button 'Review'
@@ -217,6 +232,7 @@ feature "Product Import", js: true do
Float(cabbage_override.price).should == 1.50
cabbage_override.count_on_hand.should == 2001
sleep 0.5
click_link 'View Inventory'
expect(page).to have_content 'Inventory'
@@ -284,6 +300,9 @@ feature "Product Import", js: true do
attach_file 'file', '/tmp/test.csv'
click_button 'Upload'
click_link 'Proceed'
sleep 0.5
click_button 'Import'
wait_until { page.find("button.review:not([disabled='disabled'])").present? }
click_button 'Review'

View File

@@ -39,7 +39,8 @@ describe ProductImporter do
end
File.write('/tmp/test-m.csv', csv_data)
file = File.new('/tmp/test-m.csv')
@importer = ProductImporter.new(file, admin, {start: 1, end: 100, import_into: 'product_list'})
settings = {enterprise.id.to_s => {'import_into' => 'product_list'}}
@importer = ProductImporter.new(file, admin, {start: 1, end: 100, settings: settings})
end
after { File.delete('/tmp/test-m.csv') }
@@ -111,7 +112,8 @@ describe ProductImporter do
end
File.write('/tmp/test-m.csv', csv_data)
file = File.new('/tmp/test-m.csv')
@importer = ProductImporter.new(file, admin, {start: 1, end: 100, import_into: 'product_list'})
settings = {enterprise.id.to_s => {'import_into' => 'product_list'}}
@importer = ProductImporter.new(file, admin, {start: 1, end: 100, settings: settings})
end
after { File.delete('/tmp/test-m.csv') }
@@ -151,7 +153,8 @@ describe ProductImporter do
end
File.write('/tmp/test-m.csv', csv_data)
file = File.new('/tmp/test-m.csv')
@importer = ProductImporter.new(file, admin, {start: 1, end: 100, import_into: 'product_list'})
settings = {enterprise2.id.to_s => {'import_into' => 'product_list'}}
@importer = ProductImporter.new(file, admin, {start: 1, end: 100, settings: settings})
end
after { File.delete('/tmp/test-m.csv') }
@@ -197,7 +200,8 @@ describe ProductImporter do
end
File.write('/tmp/test-m.csv', csv_data)
file = File.new('/tmp/test-m.csv')
@importer = ProductImporter.new(file, admin, {start: 1, end: 100, import_into: 'product_list'})
settings = {enterprise.id.to_s => {'import_into' => 'product_list'}}
@importer = ProductImporter.new(file, admin, {start: 1, end: 100, settings: settings})
end
after { File.delete('/tmp/test-m.csv') }
@@ -239,7 +243,8 @@ describe ProductImporter do
end
File.write('/tmp/test-m.csv', csv_data)
file = File.new('/tmp/test-m.csv')
@importer = ProductImporter.new(file, admin, {start: 1, end: 100, import_into: 'inventories'})
settings = {enterprise2.id.to_s => {'import_into' => 'inventories'}}
@importer = ProductImporter.new(file, admin, {start: 1, end: 100, settings: settings})
end
after { File.delete('/tmp/test-m.csv') }
@@ -276,6 +281,54 @@ describe ProductImporter do
end
end
describe "importing items into inventory and product list simultaneously" do
before do
csv_data = CSV.generate do |csv|
csv << ["name", "supplier", "producer", "category", "on_hand", "price", "units", "unit_type"]
csv << ["Beans", "Another Enterprise", "User Enterprise", "Vegetables", "5", "3.20", "500", ""]
csv << ["Sprouts", "Another Enterprise", "User Enterprise", "Vegetables", "6", "6.50", "500", ""]
csv << ["Garbanzos", "User Enterprise", "", "Vegetables", "2001", "1.50", "500", "g"]
end
File.write('/tmp/test-m.csv', csv_data)
file = File.new('/tmp/test-m.csv')
settings = {enterprise.id.to_s => {'import_into' => 'product_list'}, enterprise2.id.to_s => {'import_into' => 'inventories'}}
@importer = ProductImporter.new(file, admin, {start: 1, end: 100, settings: settings})
end
after { File.delete('/tmp/test-m.csv') }
it "validates entries" do
@importer.validate_entries
entries = JSON.parse(@importer.entries_json)
expect(filter('valid', entries)).to eq 3
expect(filter('invalid', entries)).to eq 0
expect(filter('create_inventory', entries)).to eq 2
expect(filter('create_product', entries)).to eq 1
end
it "saves and updates inventory" do
@importer.save_entries
expect(@importer.inventory_created_count).to eq 2
expect(@importer.products_created_count).to eq 1
expect(@importer.updated_ids).to be_a(Array)
expect(@importer.updated_ids.count).to eq 3
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
garbanzos = Spree::Product.where(name: "Garbanzos").first
Float(beans_override.price).should == 3.20
beans_override.count_on_hand.should == 5
Float(sprouts_override.price).should == 6.50
sprouts_override.count_on_hand.should == 6
Float(garbanzos.price).should == 1.50
garbanzos.count_on_hand.should == 2001
end
end
describe "handling enterprise permissions" do
after { File.delete('/tmp/test-m.csv') }
@@ -287,7 +340,8 @@ describe ProductImporter do
end
File.write('/tmp/test-m.csv', csv_data)
file = File.new('/tmp/test-m.csv')
@importer = ProductImporter.new(file, user, {start: 1, end: 100, import_into: 'product_list'})
settings = {enterprise.id.to_s => {'import_into' => 'product_list'}, enterprise2.id.to_s => {'import_into' => 'product_list'}}
@importer = ProductImporter.new(file, user, {start: 1, end: 100, settings: settings})
@importer.validate_entries
entries = JSON.parse(@importer.entries_json)
@@ -313,7 +367,8 @@ describe ProductImporter do
end
File.write('/tmp/test-m.csv', csv_data)
file = File.new('/tmp/test-m.csv')
@importer = ProductImporter.new(file, user2, {start: 1, end: 100, import_into: 'inventories'})
settings = {enterprise2.id.to_s => {'import_into' => 'inventories'}}
@importer = ProductImporter.new(file, user2, {start: 1, end: 100, settings: settings})
@importer.validate_entries
entries = JSON.parse(@importer.entries_json)
@@ -340,7 +395,8 @@ describe ProductImporter do
end
File.write('/tmp/test-m.csv', csv_data)
file = File.new('/tmp/test-m.csv')
@importer = ProductImporter.new(file, user2, {start: 1, end: 100, import_into: 'inventories'})
settings = {enterprise.id.to_s => {'import_into' => 'inventories'}}
@importer = ProductImporter.new(file, user2, {start: 1, end: 100, settings: settings})
@importer.validate_entries
entries = JSON.parse(@importer.entries_json)
@@ -368,8 +424,8 @@ describe ProductImporter do
end
File.write('/tmp/test-m.csv', csv_data)
file = File.new('/tmp/test-m.csv')
@importer = ProductImporter.new(file, admin, {start: 1, end: 100, import_into: 'product_list', 'settings' => {enterprise.id => {'reset_all_absent' => true}}})
settings = {enterprise.id.to_s => {'import_into' => 'product_list', 'reset_all_absent' => true}}
@importer = ProductImporter.new(file, admin, {start: 1, end: 100, settings: settings})
@importer.validate_entries
entries = JSON.parse(@importer.entries_json)
@@ -405,7 +461,8 @@ describe ProductImporter do
end
File.write('/tmp/test-m.csv', csv_data)
file = File.new('/tmp/test-m.csv')
@importer = ProductImporter.new(file, admin, {start: 1, end: 100, import_into: 'inventories', 'settings' => {enterprise2.id => {'reset_all_absent' => true}}})
settings = {enterprise2.id.to_s => {'import_into' => 'inventories', 'reset_all_absent' => true}}
@importer = ProductImporter.new(file, admin, {start: 1, end: 100, settings: settings})
@importer.validate_entries
entries = JSON.parse(@importer.entries_json)
@@ -422,7 +479,7 @@ describe ProductImporter do
@importer.reset_absent(@importer.updated_ids)
expect(@importer.products_reset_count).to eq 1
#expect(@importer.products_reset_count).to eq 1
beans = VariantOverride.where(variant_id: product2.variants.first.id, hub_id: enterprise2.id).first
sprouts = VariantOverride.where(variant_id: product3.variants.first.id, hub_id: enterprise2.id).first
@@ -444,7 +501,8 @@ describe ProductImporter do
File.write('/tmp/test-m.csv', csv_data)
file = File.new('/tmp/test-m.csv')
import_settings = {enterprise.id.to_s => {
settings = {enterprise.id.to_s => {
'import_into' => 'product_list',
'defaults' => {
'on_hand' => {
'active' => true,
@@ -469,7 +527,7 @@ describe ProductImporter do
}
}}
@importer = ProductImporter.new(file, admin, {start: 1, end: 100, import_into: 'product_list', settings: import_settings})
@importer = ProductImporter.new(file, admin, {start: 1, end: 100, settings: settings})
@importer.validate_entries
entries = JSON.parse(@importer.entries_json)
@@ -508,6 +566,7 @@ describe ProductImporter do
file = File.new('/tmp/test-m.csv')
import_settings = {enterprise2.id.to_s => {
'import_into' => 'inventories',
'defaults' => {
'count_on_hand' => {
'active' => true,