Skip to content

Commit

Permalink
Add warnings when updating existing product fields
Browse files Browse the repository at this point in the history
  • Loading branch information
Matt-Yorkley committed Aug 21, 2018
1 parent e0d1301 commit 2275288
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,7 @@ angular.module("admin.productImport").controller "ImportFeedbackCtrl", ($scope)
$scope.attribute_invalid = (attribute, line_number) ->
$scope.entries[line_number]['errors'][attribute] != undefined

$scope.attribute_not_updatable = (attribute, line_number) ->
$scope.entries[line_number]['warnings'][attribute] != undefined

$scope.ignore_fields = ['variant_unit', 'variant_unit_scale', 'unit_description']
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
angular.module("admin.productImport", ["ngResource"]).config ($httpProvider) ->
angular.module("admin.productImport", ["ngResource", "admin.utils"]).config ($httpProvider) ->
$httpProvider.defaults.headers.common["X-CSRF-Token"] = $("meta[name=csrf-token]").attr("content")
$httpProvider.defaults.headers.common["Accept"] = "application/json, text/javascript, */*"
59 changes: 45 additions & 14 deletions app/assets/stylesheets/admin/product_import.css.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ div.panel-section {
.neutral {
color: #bfbfbf;
}
.warning {
.error {
color: $warning-red;
}
.warning {
color: #ffa92e;
}
.success {
color: #86d83a;
}
Expand Down Expand Up @@ -85,21 +88,45 @@ div.panel-section {
td, th {
white-space: nowrap;
}
tr.error {
color: #c84C4c;
}
tr:hover td.invalid {
background-color: #ed5135;

tr {
&.error {
color: #c84C4c;
}

&:hover td.invalid {
background-color: darken(#f05c51, 5%);
}

&:hover td.not_updatable {
background-color: darken(#faffaf, 5%);
}

i {
display: block;
margin-bottom: -0.2em;
font-size: 1.4em !important;
}
}
tr i {
display: block;
margin-bottom: -0.2em;
font-size: 1.4em !important;

td {
&.invalid {
background-color: #f05c51;
box-shadow: inset 0px 0px 1px red;
color: white;
}

&.not_updatable {
background-color: #faffaf;
box-shadow: inset 0px 0px 1px #ffa92e;
}
}
td.invalid {
background-color: #f05c51;
box-shadow: inset 0px 0px 1px red;
color: white;

span.not-updatable i {
float: left;
margin-right: 0.4em;
padding-top: 0.3em;
font-size: 1.1em !important;
}
}

Expand Down Expand Up @@ -234,6 +261,10 @@ form.product-import, div.post-save-results, div.import-wrapper {

div.import-wrapper {

.alert-box {
margin: 0 0 1.75em;
}

.ng-hide:not(.ng-hide-animate) {
// We have to use !important here to override angular's display properties
// scss-lint:disable ImportantRule
Expand Down
1 change: 1 addition & 0 deletions app/controllers/admin/product_import_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ def import
@filepath = save_uploaded_file(params[:file])
@importer = ProductImport::ProductImporter.new(File.new(@filepath), spree_current_user, params[:settings])
@original_filename = params[:file].try(:original_filename)
@non_updatable_fields = @importer.validator.non_updatable_fields

check_file_errors @importer
check_spreadsheet_has_data @importer
Expand Down
27 changes: 23 additions & 4 deletions app/models/product_import/entry_validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@ def initialize(current_user, import_time, spreadsheet_data, editable_enterprises
@import_settings = import_settings
end

def non_updatable_fields
{
category: :primary_taxon_id,
unit_type: :variant_unit_scale,
variant_unit_name: :variant_unit_name,
tax_category: :tax_category_id,
shipping_category: :shipping_category_id
}
end

def validate_all(entries)
entries.each do |entry|
supplier_validation(entry)
Expand Down Expand Up @@ -160,23 +170,24 @@ def tax_and_shipping_validation(entry, type, category, index)

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
existing_product = Spree::Product.where(supplier_id: entry.supplier_id, name: entry.name, deleted_at: nil).first

# If no matching product was found, create a new product
if match.nil?
if existing_product.nil?
mark_as_new_product(entry)
return
end

# Otherwise, if a variant exists with matching display_name and unit_value, update it
match.variants.each do |existing_variant|
existing_product.variants.each do |existing_variant|
if entry_matches_existing_variant?(entry, existing_variant) && existing_variant.deleted_at.nil?
apply_product_field_warnings entry, existing_variant
return mark_as_existing_variant(entry, existing_variant)
end
end

# Otherwise, a variant with sufficiently matching attributes doesn't exist; create a new one
mark_as_new_variant(entry, match.id)
mark_as_new_variant(entry, existing_product.id)
end

def mark_as_new_product(entry)
Expand All @@ -203,6 +214,14 @@ def mark_as_existing_variant(entry, existing_variant)
end
end

def apply_product_field_warnings(entry, existing_variant)
non_updatable_fields.each do |display_name, attribute|
next if existing_variant.product.send(attribute) == entry.send(attribute)

entry.warnings.add display_name, I18n.t('admin.product_import.model.not_updatable')
end
end

def permission_by_name?(supplier_name)
@editable_enterprises.key?(supplier_name)
end
Expand Down
12 changes: 10 additions & 2 deletions app/models/product_import/product_importer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class ProductImporter
include ActiveModel::Conversion
include ActiveModel::Validations

attr_reader :updated_ids, :import_settings
attr_reader :updated_ids, :import_settings, :validator

def initialize(file, current_user, import_settings = {})
unless file.is_a?(File)
Expand Down Expand Up @@ -50,6 +50,13 @@ def item_count
@sheet ? @sheet.last_row - 1 : 0
end

def warnings?
@entries.each do |entry|
return true if entry.warnings.count
end
false
end

def reset_counts
# Return indexed data about existing product count, reset count, and updates count per supplier
@reset_counts.each do |supplier_id, values|
Expand Down Expand Up @@ -85,7 +92,8 @@ def entries_json
entries[entry.line_number] = {
attributes: entry.displayable_attributes,
validates_as: entry.validates_as,
errors: entry.invalid_attributes
errors: entry.invalid_attributes,
warnings: entry.non_updatable_attributes
}
end
entries.to_json
Expand Down
13 changes: 11 additions & 2 deletions app/models/product_import/spreadsheet_entry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ class SpreadsheetEntry
attr_accessor :id, :product_id, :producer, :producer_id, :supplier, :supplier_id, :name, :display_name, :sku,
:unit_value, :unit_description, :variant_unit, :variant_unit_scale, :variant_unit_name,
:display_as, :category, :primary_taxon_id, :price, :on_hand, :count_on_hand, :on_demand,
:tax_category_id, :shipping_category_id, :description, :import_date
:tax_category_id, :shipping_category_id, :description, :import_date, :warnings

def initialize(attrs)
@validates_as = ''
@warnings = ActiveModel::Errors.new(self)
assign_units attrs
end

Expand Down Expand Up @@ -55,6 +56,14 @@ def invalid_attributes
invalid_attrs.except(*non_product_attributes, *non_display_attributes)
end

def non_updatable_attributes
non_updatable_attrs = {}
warnings.messages.each do |attr, message|
non_updatable_attrs[attr.to_s] = "#{attr.to_s.capitalize} #{message.first}"
end
non_updatable_attrs.except(*non_product_attributes, *non_display_attributes)
end

private

def assign_units(attrs)
Expand All @@ -72,7 +81,7 @@ def non_display_attributes
end

def non_product_attributes
['line_number', 'valid', 'errors', 'product_object', 'product_validations', 'inventory_validations', 'validates_as', 'save_type', 'on_hand_nil', 'has_overrides']
['line_number', 'valid', 'errors', 'warnings', 'product_object', 'product_validations', 'inventory_validations', 'validates_as', 'save_type', 'on_hand_nil', 'has_overrides']
end
end
end
10 changes: 7 additions & 3 deletions app/views/admin/product_import/_entries_table.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@
%th= heading
%tr{ng: {repeat: "(line_number, entry) in (entries | entriesFilterValid:'#{entries}')"}}
%td
%i{ng: {class: "{'fa fa-warning warning': (count(entry.errors) > 0), 'fa fa-check-circle success': (count(entry.errors) == 0)}"}}
%i{ng: {class: "{'fa fa-warning error': (count(entry.errors) > 0), 'fa fa-check-circle success': (count(entry.errors) == 0)}"}}
%td
{{line_number}}
%td{ng: {repeat: "(attribute, value) in entry.attributes", class: "{'invalid': attribute_invalid(attribute, line_number)}"}}
{{value}}
%td{ng: {repeat: "(attribute, value) in entry.attributes", class: "{'invalid': attribute_invalid(attribute, line_number), 'not_updatable': attribute_not_updatable(attribute, line_number)}"}}
%span{ng: {show: "!attribute_not_updatable(attribute, line_number)"}}
{{value}}
%span.not-updatable{'ofn-with-tip' => t('.not_updatable'), ng: {show: "attribute_not_updatable(attribute, line_number)"}}
%i.fa.fa-warning.warning
{{value}}
8 changes: 7 additions & 1 deletion app/views/admin/product_import/_import_review.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@

%div{ng: {controller: 'ImportFeedbackCtrl'}}

- if @importer.warnings?
.alert-box.warning
= t('.not_updatable_tip')
%em= @non_updatable_fields.keys.join(', ') + "."
= t('.fields_ignored')

%div.panel-section{ng: {controller: 'DropdownPanelsCtrl'}}
%div.panel-header{ng: {click: 'togglePanel()', class: '{active: active && count((entries | entriesFilterValid:"all"))}'}}
%div.header-caret
Expand All @@ -21,7 +27,7 @@
%div.panel-header{ng: {click: 'togglePanel()', class: '{active: active && count((entries | entriesFilterValid:"invalid"))}'}}
%div.header-caret
%i{ng: {class: "{'icon-chevron-down': active, 'icon-chevron-right': !active}", hide: 'count((entries | entriesFilterValid:"invalid")) == 0'}}
%div.header-icon.warning
%div.header-icon.error
%i.fa.fa-warning
%div.header-count
%strong.invalid-count
Expand Down
6 changes: 6 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,7 @@ en:
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
not_updatable: cannot be updated on existing products
blank: can't be blank
products_no_permission: you do not have permission to manage products for this enterprise
inventory_no_permission: you do not have permission to create inventory for this producer
Expand Down Expand Up @@ -547,6 +548,11 @@ en:
inventory_to_reset: Existing inventory items will have their stock reset to zero
line: Line
item_line: Item line
import_review:
not_updatable_tip: "The following fields cannot be updated via bulk import for existing products:"
fields_ignored: These fields will be ignored when the imported products are saved.
entries_table:
not_updatable: This field is not updatable via bulk import on existing products
save_results:
final_results: Import final results
products_created: Products created
Expand Down

0 comments on commit 2275288

Please sign in to comment.