Merge branch 'master' into 2-0-stable-nov-8th

This commit is contained in:
luisramos0
2018-11-08 11:18:54 +00:00
101 changed files with 4970 additions and 760 deletions

View File

@@ -1,6 +1,6 @@
module OpenFoodNetwork
class Calculator::Weight < Spree::Calculator
preference :per_kg, :decimal, :default => 0.0
module Calculator
class Weight < Spree::Calculator
preference :per_kg, :decimal, default: 0.0
attr_accessible :preferred_per_kg
def self.description
@@ -10,14 +10,15 @@ module OpenFoodNetwork
def compute(object)
line_items = line_items_for object
total_weight = line_items.sum { |li| ((li.variant.andand.weight || 0) * li.quantity) }
total_weight * self.preferred_per_kg
total_weight * preferred_per_kg
end
private
def line_items_for(object)
if object.respond_to? :line_items
if object.respond_to? :order
object.order.line_items
elsif object.respond_to? :line_items
object.line_items
elsif object.respond_to?(:variant) && object.respond_to?(:quantity)
[object]

View File

@@ -80,6 +80,8 @@ class Enterprise < ActiveRecord::Base
before_validation :set_unused_address_fields
after_validation :geocode_address
validates :instagram, format: /\A@[a-zA-Z0-9._]{1,30}\z/, allow_blank: true
after_touch :touch_distributors
after_create :set_default_contact
after_create :relate_to_owners_enterprises
@@ -330,6 +332,10 @@ class Enterprise < ActiveRecord::Base
abn.present?
end
def instagram=(value)
write_attribute(:instagram, value.try(:gsub, instagram_regex, '@\1'))
end
protected
def devise_mailer
@@ -338,6 +344,10 @@ class Enterprise < ActiveRecord::Base
private
def instagram_regex
%r{\A(?:https?://)?(?:www\.)?instagram\.com/([a-zA-Z0-9._]{1,30})/?\z}
end
def name_is_unique
dups = Enterprise.where(name: name)
dups = dups.where('id != ?', id) unless new_record?

View File

@@ -6,7 +6,8 @@ class EnterpriseRelationship < ActiveRecord::Base
validates_presence_of :parent_id, :child_id
validates_uniqueness_of :child_id, scope: :parent_id, message: I18n.t('validation_msg_relationship_already_established')
after_save :apply_variant_override_permissions
after_save :update_permissions_of_child_variant_overrides
before_destroy :revoke_all_child_variant_overrides
scope :with_enterprises,
joins('LEFT JOIN enterprises AS parent_enterprises ON parent_enterprises.id = enterprise_relationships.parent_id').
@@ -26,7 +27,6 @@ class EnterpriseRelationship < ActiveRecord::Base
scope :by_name, with_enterprises.order('child_enterprises.name, parent_enterprises.name')
# Load an array of the relatives of each enterprise (ie. any enterprise related to it in
# either direction). This array is split into distributors and producers, and has the format:
# {enterprise_id => {distributors: [id, ...], producers: [id, ...]} }
@@ -76,14 +76,24 @@ class EnterpriseRelationship < ActiveRecord::Base
private
def apply_variant_override_permissions
variant_overrides = VariantOverride.unscoped.for_hubs(child)
.joins(variant: :product).where("spree_products.supplier_id IN (?)", parent)
def update_permissions_of_child_variant_overrides
if has_permission?(:create_variant_overrides)
variant_overrides.update_all(permission_revoked_at: nil)
allow_all_child_variant_overrides
else
variant_overrides.update_all(permission_revoked_at: Time.now)
revoke_all_child_variant_overrides
end
end
def allow_all_child_variant_overrides
child_variant_overrides.update_all(permission_revoked_at: nil)
end
def revoke_all_child_variant_overrides
child_variant_overrides.update_all(permission_revoked_at: Time.now)
end
def child_variant_overrides
VariantOverride.unscoped.for_hubs(child)
.joins(variant: :product).where("spree_products.supplier_id IN (?)", parent)
end
end

View File

@@ -5,8 +5,8 @@
module ProductImport
class EntryProcessor
attr_reader :inventory_created, :inventory_updated, :products_created,
:variants_created, :variants_updated, :supplier_products,
:total_supplier_products, :products_reset_count
:variants_created, :variants_updated, :enterprise_products,
:total_enterprise_products, :products_reset_count
def initialize(importer, validator, import_settings, spreadsheet_data, editable_enterprises, import_time, updated_ids)
@importer = importer
@@ -23,13 +23,13 @@ module ProductImport
@variants_created = 0
@variants_updated = 0
@products_reset_count = 0
@supplier_products = {}
@total_supplier_products = 0
@enterprise_products = {}
@total_enterprise_products = 0
end
def save_all(entries)
entries.each do |entry|
if import_into_inventory?(entry)
if settings.importing_into_inventory?
save_to_inventory(entry)
else
save_to_product_list(entry)
@@ -40,24 +40,24 @@ module ProductImport
end
def count_existing_items
@spreadsheet_data.suppliers_index.each do |_supplier_name, attrs|
supplier_id = attrs[:id]
next unless supplier_id && permission_by_id?(supplier_id)
@spreadsheet_data.enterprises_index.each do |_enterprise_name, attrs|
enterprise_id = attrs[:id]
next unless enterprise_id && permission_by_id?(enterprise_id)
products_count =
if settings.importing_into_inventory?
VariantOverride.where('variant_overrides.hub_id IN (?)', supplier_id).count
VariantOverride.for_hubs([enterprise_id]).count
else
Spree::Variant.
not_deleted.
not_master.
joins(:product).
where('spree_products.supplier_id IN (?)', supplier_id).
where('spree_products.supplier_id IN (?)', enterprise_id).
count
end
@supplier_products[supplier_id] = products_count
@total_supplier_products += products_count
@enterprise_products[enterprise_id] = products_count
@total_enterprise_products += products_count
end
end
@@ -88,8 +88,8 @@ module ProductImport
@products_created + @variants_created + @variants_updated + @inventory_created + @inventory_updated
end
def permission_by_id?(supplier_id)
@editable_enterprises.value?(Integer(supplier_id))
def permission_by_id?(enterprise_id)
@editable_enterprises.value?(Integer(enterprise_id))
end
private
@@ -121,10 +121,6 @@ module ProductImport
@variants_updated += 1
end
def import_into_inventory?(entry)
entry.supplier_id && settings.importing_into_inventory?
end
def save_new_inventory_item(entry)
new_item = entry.product_object
assign_defaults(new_item, entry)
@@ -158,14 +154,17 @@ module ProductImport
# If we've already added a new product with these attributes
# from this spreadsheet, mark this entry as a new variant with
# the new product id, as this is a now variant of that product...
if @already_created[entry.supplier_id] && @already_created[entry.supplier_id][entry.name]
product_id = @already_created[entry.supplier_id][entry.name]
if @already_created[entry.enterprise_id] &&
@already_created[entry.enterprise_id][entry.name]
product_id = @already_created[entry.enterprise_id][entry.name]
@validator.mark_as_new_variant(entry, product_id)
return
end
product = Spree::Product.new
product.assign_attributes(entry.attributes.except('id'))
product.supplier_id = entry.producer_id
assign_defaults(product, entry)
if product.save
@@ -176,7 +175,7 @@ module ProductImport
assign_errors product.errors.full_messages, entry.line_number
end
@already_created[entry.supplier_id] = { entry.name => product.id }
@already_created[entry.enterprise_id] = { entry.name => product.id }
end
def save_variant(entry)
@@ -214,7 +213,10 @@ module ProductImport
when 'overwrite_all'
object.assign_attributes(attribute => setting['value'])
when 'overwrite_empty'
if object.public_send(attribute).blank? || ((attribute == 'on_hand' || attribute == 'count_on_hand') && entry.on_hand_nil)
if object.public_send(attribute).blank? ||
((attribute == 'on_hand' || attribute == 'count_on_hand') &&
entry.on_hand_nil)
object.assign_attributes(attribute => setting['value'])
end
end
@@ -223,7 +225,10 @@ module ProductImport
def display_in_inventory(variant_override, is_new = false)
unless is_new
existing_item = InventoryItem.where(variant_id: variant_override.variant_id, enterprise_id: variant_override.hub_id).first
existing_item = InventoryItem.where(
variant_id: variant_override.variant_id,
enterprise_id: variant_override.hub_id
).first
if existing_item
existing_item.assign_attributes(visible: true)
@@ -232,7 +237,11 @@ module ProductImport
end
end
InventoryItem.new(variant_id: variant_override.variant_id, enterprise_id: variant_override.hub_id, visible: true).save
InventoryItem.new(
variant_id: variant_override.variant_id,
enterprise_id: variant_override.hub_id,
visible: true
).save
end
def ensure_variant_updated(product, entry)

View File

@@ -27,10 +27,11 @@ module ProductImport
def validate_all(entries)
entries.each do |entry|
supplier_validation(entry)
assign_enterprise_field(entry)
enterprise_validation(entry)
unit_fields_validation(entry)
next if entry.supplier_id.blank?
next if entry.enterprise_id.blank?
if import_into_inventory?
producer_validation(entry)
@@ -44,6 +45,14 @@ module ProductImport
end
end
def assign_enterprise_field(entry)
entry.enterprise = entry.public_send(enterprise_field)
end
def enterprise_field
import_into_inventory? ? :distributor : :producer
end
def mark_as_new_variant(entry, product_id)
new_variant = Spree::Variant.new(entry.attributes.except('id', 'product_id'))
new_variant.product_id = product_id
@@ -59,37 +68,56 @@ module ProductImport
private
def supplier_validation(entry)
def enterprise_validation(entry)
return if name_presence_error entry
return if enterprise_not_found_error entry
return if permissions_error entry
return if primary_producer_error entry
entry.supplier_id = @spreadsheet_data.suppliers_index[entry.supplier][:id]
entry.enterprise_id =
@spreadsheet_data.enterprises_index[entry.enterprise][:id]
entry.public_send(
"#{enterprise_field}_id=",
@spreadsheet_data.enterprises_index[entry.enterprise][:id]
)
end
def name_presence_error(entry)
return if entry.supplier.present?
mark_as_invalid(entry, attribute: "supplier", error: I18n.t(:error_required))
return if entry.enterprise.present?
mark_as_invalid(entry,
attribute: enterprise_field,
error: I18n.t(:error_required))
true
end
def enterprise_not_found_error(entry)
return if @spreadsheet_data.suppliers_index[entry.supplier][:id]
mark_as_invalid(entry, attribute: "supplier", error: I18n.t(:error_not_found_in_database, name: entry.supplier))
return if @spreadsheet_data.enterprises_index[entry.enterprise][:id]
mark_as_invalid(entry,
attribute: enterprise_field,
error: I18n.t(:error_not_found_in_database,
name: entry.enterprise))
true
end
def permissions_error(entry)
return if permission_by_name?(entry.supplier)
mark_as_invalid(entry, attribute: "supplier", error: I18n.t(:error_no_permission_for_enterprise, name: entry.supplier))
return if permission_by_name?(entry.enterprise)
mark_as_invalid(entry,
attribute: enterprise_field,
error: I18n.t(:error_no_permission_for_enterprise,
name: entry.enterprise))
true
end
def primary_producer_error(entry)
return if import_into_inventory?
return if @spreadsheet_data.suppliers_index[entry.supplier][:is_primary_producer]
mark_as_invalid(entry, attribute: "supplier", error: I18n.t(:error_not_primary_producer, name: entry.supplier))
return if @spreadsheet_data.
enterprises_index[entry.enterprise][:is_primary_producer]
mark_as_invalid(entry,
attribute: enterprise_field,
error: I18n.t(:error_not_primary_producer,
name: entry.enterprise))
true
end
@@ -126,7 +154,11 @@ module ProductImport
return
end
unless inventory_permission?(entry.supplier_id, @spreadsheet_data.producers_index[producer_name])
unless inventory_permission?(
entry.enterprise_id,
@spreadsheet_data.producers_index[producer_name]
)
mark_as_invalid(entry, attribute: "producer", error: "\"#{producer_name}\": #{I18n.t('admin.product_import.model.inventory_no_permission')}")
return
end
@@ -186,7 +218,9 @@ module ProductImport
end
def product_validation(entry)
products = Spree::Product.where(supplier_id: entry.supplier_id, name: entry.name, deleted_at: nil)
products = Spree::Product.where(supplier_id: entry.enterprise_id,
name: entry.name,
deleted_at: nil)
if products.empty?
mark_as_new_product(entry)
@@ -207,6 +241,7 @@ module ProductImport
def mark_as_new_product(entry)
new_product = Spree::Product.new
new_product.assign_attributes(entry.attributes.except('id'))
new_product.supplier_id = entry.producer_id
if new_product.valid?
entry.validates_as = 'new_product' unless entry.errors?
@@ -222,7 +257,7 @@ module ProductImport
if existing_variant.valid?
entry.product_object = existing_variant
entry.validates_as = 'existing_variant' unless entry.errors?
updates_count_per_supplier(entry.supplier_id) unless entry.errors?
updates_count_per_enterprise(entry.enterprise_id) unless entry.errors?
else
mark_as_invalid(entry, product_validations: existing_variant.errors)
end
@@ -243,16 +278,18 @@ module ProductImport
existing_product.public_send(attribute).blank? && entry.public_send(attribute).blank?
end
def permission_by_name?(supplier_name)
@editable_enterprises.key?(supplier_name)
def permission_by_name?(enterprise_name)
@editable_enterprises.key?(enterprise_name)
end
def permission_by_id?(supplier_id)
@editable_enterprises.value?(Integer(supplier_id))
def permission_by_id?(enterprise_id)
@editable_enterprises.value?(Integer(enterprise_id))
end
def inventory_permission?(supplier_id, producer_id)
@current_user.admin? || ( @inventory_permissions[supplier_id] && @inventory_permissions[supplier_id].include?(producer_id) )
def inventory_permission?(enterprise_id, producer_id)
@current_user.admin? ||
( @inventory_permissions[enterprise_id] &&
@inventory_permissions[enterprise_id].include?(producer_id) )
end
def mark_as_invalid(entry, options = {})
@@ -261,7 +298,7 @@ module ProductImport
end
def import_into_inventory?
@import_settings[:settings]['import_into'] == 'inventories'
@import_settings[:settings].andand['import_into'] == 'inventories'
end
def validate_inventory_item(entry, variant_override)
@@ -273,9 +310,16 @@ module ProductImport
end
def create_inventory_item(entry, existing_variant)
existing_variant_override = VariantOverride.where(variant_id: existing_variant.id, hub_id: entry.supplier_id).first
existing_variant_override = VariantOverride.where(
variant_id: existing_variant.id,
hub_id: entry.enterprise_id
).first
variant_override = existing_variant_override || VariantOverride.new(
variant_id: existing_variant.id,
hub_id: entry.enterprise_id
)
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'))
@@ -287,18 +331,20 @@ module ProductImport
if variant_override.id
entry.validates_as = 'existing_inventory_item'
entry.product_object = variant_override
updates_count_per_supplier(entry.supplier_id) unless entry.errors?
updates_count_per_enterprise(entry.enterprise_id) unless entry.errors?
else
entry.validates_as = 'new_inventory_item'
entry.product_object = variant_override
end
end
def updates_count_per_supplier(supplier_id)
if @reset_counts[supplier_id] && @reset_counts[supplier_id][:updates_count]
@reset_counts[supplier_id][:updates_count] += 1
def updates_count_per_enterprise(enterprise_id)
if @reset_counts[enterprise_id] &&
@reset_counts[enterprise_id][:updates_count]
@reset_counts[enterprise_id][:updates_count] += 1
else
@reset_counts[supplier_id] = { updates_count: 1 }
@reset_counts[enterprise_id] = { updates_count: 1 }
end
end

View File

@@ -4,10 +4,10 @@ module ProductImport
@excluded_items_ids = excluded_items_ids
end
def reset(supplier_ids)
@supplier_ids = supplier_ids
def reset(enterprise_ids)
@enterprise_ids = enterprise_ids
if supplier_ids.present?
if enterprise_ids.present?
relation.update_all(count_on_hand: 0)
else
0
@@ -16,10 +16,10 @@ module ProductImport
private
attr_reader :excluded_items_ids, :supplier_ids
attr_reader :excluded_items_ids, :enterprise_ids
def relation
relation = VariantOverride.where(hub_id: supplier_ids)
relation = VariantOverride.where(hub_id: enterprise_ids)
return relation if excluded_items_ids.blank?
relation.where('id NOT IN (?)', excluded_items_ids)

View File

@@ -65,27 +65,29 @@ module ProductImport
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|
# Return indexed data about existing product count, reset count, and
# updates count per enterprise
@reset_counts.each do |enterprise_id, values|
values[:updates_count] = 0 if values[:updates_count].blank?
if values[:updates_count] && values[:existing_products]
@reset_counts[supplier_id][:reset_count] = values[:existing_products] - values[:updates_count]
@reset_counts[enterprise_id][:reset_count] =
values[:existing_products] - values[:updates_count]
end
end
@reset_counts
end
def suppliers_index
@spreadsheet_data.suppliers_index
def enterprises_index
@spreadsheet_data.enterprises_index
end
def supplier_products
@processor.andand.supplier_products
def enterprise_products
@processor.andand.enterprise_products
end
def total_supplier_products
@processor.total_supplier_products
def total_enterprise_products
@processor.total_enterprise_products
end
def all_entries
@@ -165,8 +167,8 @@ module ProductImport
@processor.reset_absent_items
end
def permission_by_id?(supplier_id)
@editable_enterprises.value?(Integer(supplier_id))
def permission_by_id?(enterprise_id)
@editable_enterprises.value?(Integer(enterprise_id))
end
private
@@ -180,7 +182,7 @@ module ProductImport
build_entries
end
@spreadsheet_data = SpreadsheetData.new(@entries)
@spreadsheet_data = SpreadsheetData.new(@entries, @import_settings)
@validator = EntryValidator.new(@current_user, @import_time, @spreadsheet_data, @editable_enterprises, @inventory_permissions, @reset_counts, @import_settings)
@processor = EntryProcessor.new(self, @validator, @import_settings, @spreadsheet_data, @editable_enterprises, @import_time, @updated_ids)

View File

@@ -4,10 +4,10 @@ module ProductImport
@excluded_items_ids = excluded_items_ids
end
def reset(supplier_ids)
@supplier_ids = supplier_ids
def reset(enterprise_ids)
@enterprise_ids = enterprise_ids
if supplier_ids.present?
if enterprise_ids.present?
relation.update_all(count_on_hand: 0)
else
0
@@ -16,13 +16,13 @@ module ProductImport
private
attr_reader :excluded_items_ids, :supplier_ids
attr_reader :excluded_items_ids, :enterprise_ids
def relation
relation = Spree::Variant
.joins(:product)
.where(
spree_products: { supplier_id: supplier_ids },
spree_products: { supplier_id: enterprise_ids },
spree_variants: { is_master: false, deleted_at: nil }
)

View File

@@ -6,8 +6,8 @@ module ProductImport
def defaults(entry)
@import_settings.key?(:settings) &&
settings[entry.supplier_id.to_s] &&
settings[entry.supplier_id.to_s]['defaults']
settings[entry.enterprise_id.to_s] &&
settings[entry.enterprise_id.to_s]['defaults']
end
def settings

View File

@@ -7,12 +7,13 @@
module ProductImport
class SpreadsheetData
def initialize(entries)
def initialize(entries, import_settings)
@entries = entries
@import_settings = import_settings
end
def suppliers_index
@suppliers_index || create_suppliers_index
def enterprises_index
@enterprises_index || create_enterprises_index
end
def producers_index
@@ -33,15 +34,24 @@ module ProductImport
private
def create_suppliers_index
@suppliers_index = {}
def import_into_inventory?
@import_settings[:settings].andand['import_into'] == 'inventories'
end
def create_enterprises_index
@enterprises_index = {}
@entries.each do |entry|
supplier_name = entry.supplier
next if @suppliers_index.key? supplier_name
enterprise = Enterprise.find_by_name(supplier_name, select: 'id, name, is_primary_producer')
@suppliers_index[supplier_name] = { id: enterprise.try(:id), is_primary_producer: enterprise.try(:is_primary_producer) }
enterprise_name = import_into_inventory? ? entry.distributor : entry.producer
next if @enterprises_index.key? enterprise_name
enterprise = Enterprise.find_by_name(enterprise_name, select: 'id, is_primary_producer')
@enterprises_index[enterprise_name] =
{ id: enterprise.try(:id),
is_primary_producer: enterprise.try(:is_primary_producer) }
end
@suppliers_index
@enterprises_index
end
def create_producers_index

View File

@@ -8,13 +8,17 @@ module ProductImport
include ActiveModel::Conversion
include ActiveModel::Validations
attr_accessor :line_number, :valid, :validates_as, :product_object, :product_validations, :on_hand_nil,
:has_overrides, :units, :unscaled_units, :unit_type, :tax_category, :shipping_category
attr_accessor :line_number, :valid, :validates_as, :product_object,
:product_validations, :on_hand_nil, :has_overrides, :units,
:unscaled_units, :unit_type, :tax_category, :shipping_category
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
attr_accessor :id, :product_id, :producer, :producer_id, :distributor,
:distributor_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, :enterprise, :enterprise_id
def initialize(attrs)
@validates_as = ''
@@ -77,11 +81,16 @@ module ProductImport
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', 'variant_unit_scale', 'variant_unit', 'unit_value']
['id', 'product_id', 'unscaled_units', 'variant_id', 'enterprise',
'enterprise_id', 'producer_id', 'distributor_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
['line_number', 'valid', 'errors', 'product_object', 'product_validations', 'inventory_validations', 'validates_as', 'save_type', 'on_hand_nil', 'has_overrides']
['line_number', 'valid', 'errors', 'product_object',
'product_validations', 'inventory_validations', 'validates_as',
'save_type', 'on_hand_nil', 'has_overrides']
end
end
end