Files
old-ribica/back-office/lib/tasks/ribica.rake
2016-02-02 17:09:06 +01:00

389 lines
11 KiB
Ruby

require 'csv'
def get_column_lookup
columns = [
:name,
:name_on_ribica,
:picture,
:brand,
:code,
:current_input_price,
:list_price,
:units_in_pack,
:description,
:stock,
:on_display,
:tags,
:traits,
:weight,
:delivery_time_estimation,
:name_unit,
:short_name_unit,
:description_suffix_unit,
:number_of_pieces_suffix_unit,
:name_sub_category,
:order_sub_category,
:name_supplier,
:address_supplier,
:postal_code_supplier,
:town_supplier,
:phone_supplier,
:contact_person_supplier,
:email_supplier,
:note_supplier
]
columns.map.with_index { |x, i| [x, i] }.to_h
end
def lookup_delivery_time_estimation(row, lookup)
dte = DeliveryTimeEstimation.where(
duration_in_days: row[lookup[:delivery_time_estimation]]
).take
if dte.nil?
dte = DeliveryTimeEstimation.new
dte.duration_in_days = row[lookup[:delivery_time_estimation]]
dte.save!
end
if dte.duration_in_days == 0
raise "Delivery time estimation input is missing or incorrect: #{dte.delivery_time_estimation}"
end
return dte
end
def lookup_unit(row, lookup)
unit = Unit.where(
name: row[lookup[:name_unit]],
short_name: row[lookup[:short_name_unit]],
description_suffix: row[lookup[:description_suffix_unit]],
number_of_pieces_suffix: row[lookup[:number_of_pieces_suffix_unit]]).take
if unit.nil?
new_unit = Unit.new
new_unit.name = row[lookup[:name_unit]]
new_unit.short_name = "kom" #row[lookup[:short_name_unit]]
new_unit.description_suffix = row[lookup[:description_suffix_unit]]
new_unit.number_of_pieces_suffix = row[lookup[:number_of_pieces_suffix_unit]]
new_unit.save!
new_unit
else
unit
end
end
def lookup_brand(row, lookup)
brand = Brand.find_by name: row[lookup[:brand]]
if brand.nil?
new_brand = Brand.new
new_brand.name = row[lookup[:brand]]
new_brand.save!
new_brand
else
brand
end
end
def lookup_supplier(row, lookup)
supplier = Supplier.find_by name: row[lookup[:name_supplier]]
if supplier.nil?
new_supplier = Supplier.new
new_supplier.name = row[lookup[:name_supplier]]
new_supplier.address = row[lookup[:address_supplier]]
new_supplier.postal_code = row[lookup[:postal_code_supplier]]
new_supplier.town = row[lookup[:town_supplier]]
new_supplier.phone = row[lookup[:phone_supplier]]
new_supplier.contact_person = row[lookup[:contact_person_supplier]]
new_supplier.email = row[lookup[:email_supplier]]
new_supplier.note = row[lookup[:note_supplier]]
new_supplier.save!
new_supplier
else
supplier
end
end
def resolve_subcategory(str)
raise "Subcategory is missing!" if str.nil?
parts = str.split(">").map{ |s| s.strip }
subcategory = parts[2]
category = parts[1]
section = parts[0]
if subcategory.to_s == '' || category.to_s == '' || section.to_s == ''
raise "Invalid subcategory : #{str}"
end
subcategory = subcategory.downcase
category = category.downcase
section = section.downcase
sc = SubCategory.eager_load(category: :section)
.where("lower(sub_categories.name) = '#{subcategory}' and lower(categories.name) = '#{category}' and lower(sections.name) = '#{section}'")
.take
return sc unless sc.nil?
section_in_db = Section.where("lower(name) = '#{section}'").take
if section_in_db.nil?
section_in_db = Section.new
section_in_db.name = section.capitalize
section_in_db.save!
end
cat_in_db =
Category
.eager_load(:section)
.where("lower(categories.name) = '#{category}' and lower(sections.name) = '#{section}'")
.take
if cat_in_db.nil?
cat_in_db = Category.new
cat_in_db.name = category.capitalize
cat_in_db.section_id = section_in_db.id
cat_in_db.save!
end
sub_cat_in_db =
SubCategory
.eager_load(:category)
.where("lower(sub_categories.name) = '#{subcategory}' and lower(categories.name) = '#{category}'")
.take
if sub_cat_in_db.nil?
sub_cat_in_db = SubCategory.new
sub_cat_in_db.name = subcategory.capitalize
sub_cat_in_db.category_id = cat_in_db.id
sub_cat_in_db.save!
end
sub_cat_in_db
#item.sub_category.order = row[lookup[:order_sub_category]]
end
def handle_multimedia(item, row, index, logger, lookup)
multimedia = row[lookup[:picture]]
return if multimedia.to_s == ""
parts = multimedia.split(";").map{ |s| s.strip }
parts.each do |part|
mmd = MultiMediaDescription.new
if part != "" and not part.start_with? "https://"
raise "Invalid url for the image: #{part}"
end
mmd.url = part
item.multi_media_descriptions.each(&:destroy)
item.multi_media_descriptions << mmd
end
end
def import_single_item(row, index, logger)
succes = true
begin
lookup = get_column_lookup
code = row[lookup[:code]]
item = (Item.find_by code: code) || Item.new
item.name = row[lookup[:name_on_ribica]]
item.code = code
if item.new_record?
item.current_input_price = 0 #row[lookup[:current_input_price]] || 11.00
item.list_price = 0 #row[lookup[:list_price]] || 12.00
end
item.units_in_pack = row[lookup[:units_in_pack]]
item.description = row[lookup[:description]]
item.description ||= item.name
item.stock = row[lookup[:stock]]
item.on_display = row[lookup[:on_display]]
item.tags = row[lookup[:tags]]
item.traits = row[lookup[:traits]]
item.weight = row[lookup[:weight]] || 1.0
item.delivery_time_estimation = lookup_delivery_time_estimation(row, lookup)
item.sub_category = resolve_subcategory(row[lookup[:name_sub_category]])
# todo multimedia, item groups
handle_multimedia(item, row, index, logger, lookup)
item.unit = lookup_unit(row, lookup)
item.supplier = lookup_supplier(row, lookup)
item.brand = lookup_brand(row, lookup)
item.save(validate: false)
# logger.info "Successfully imported item with on row position #{index}: #{row[lookup[:name_on_ribica]]}"
success = true
rescue Exception => e
logger.error "Could not import item on row number #{index} (#{row[lookup[:name_on_ribica]]}), reason: #{e}"
puts "Could not import item on row number #{index} (#{row[lookup[:name_on_ribica]]}), reason: #{e}"
success = false
end
success
end
def trim_whitespace(row)
row.map! do |value|
trimmed = value.strip if not value.nil? # value.to_s.strip
# puts "trimming '#{value}' to '#{trimmed}'"
trimmed
end
end
def do_import(validate_only)
begin
input_file = ENV['INPUT']
if input_file.to_s == ""
puts "Input file is missing! Please provide input file in form INPUT=somefile.csv"
puts RakeTasksHelper.task_error_message
return
end
lookup = get_column_lookup
path = Rails.root.join(input_file)
log_filename = Rails.root.join("import.log")
log_filename = Rails.root.join("import_validate.log") if validate_only
logger = Logger.new(log_filename)
logger.info "Item import starting at #{Time.now}"
logger.info "Will be importing items from #{path}"
i = 1
should_rollback = false
Item.transaction do
CSV.foreach(path) do |row|
if i != 1
trim_whitespace(row)
if import_single_item(row, i, logger) == false
should_rollback = true
end
end
i += 1
end
if validate_only || should_rollback
if should_rollback
puts "Import failed, please check the import log file for error details."
logger.info "Rolling back because of errors"
puts RakeTasksHelper.task_error_message
end
raise ActiveRecord::Rollback
end
end
rescue Exception => e
puts "Import failed, please check the import log file for error details."
puts "Error while importing: #{e}"
logger.error "Error while importing: #{e}"
puts RakeTasksHelper.task_error_message
end
puts "Import done"
logger.info "Import done"
end
namespace :ribica do
desc "Creates menu structure using the sections and subsections from items."
task copy_sections_to_menu: :environment do
Section.transaction do
Section.all.each do |section|
mi = MenuItem.new
mi.title = section.name
mi.url = "/sekcija/#{section.id}/#{section.name}"
mi.ordinal = section.order
section.categories.each do |category|
msi = MenuSubItem.new
msi.title = category.name
msi.url = "/sekcija/#{section.name}/kategorija/#{category.id}/#{category.name}"
msi.ordinal = section.order
mi.menu_sub_items << msi
category.sub_categories.each do |sub_category|
mssi = MenuSubSubItem.new
mssi.title = sub_category.name
mssi.url = "/podkategorija/#{sub_category.id}/#{sub_category.name}"
mssi.ordinal = sub_category.order
msi.menu_sub_sub_items << mssi
end
end
mi.save!
end
end
end
end
namespace :ribica do
desc "Clears database."
task clear_database: :environment do
conn = ActiveRecord::Base.connection
tables = conn.execute("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';").map { |r| r["table_name"] }
tables.delete "schema_migrations"
tables.each { |t| conn.execute("TRUNCATE TABLE #{t}") }
end
end
namespace :ribica do
desc "Checks for errors in csv file. "
task validate_items: :environment do
do_import true
end
end
namespace :ribica do
desc "Imports items from csv if everything is ok. "
task import_items: :environment do
do_import false
end
end
namespace :ribica do
desc "Updates prices from csv. "
task update_prices: :environment do
Item.update_prices(ENV['INPUT'])
end
end
namespace :ribica do
desc "Imports items from csv if everything is ok. "
task reindex: :environment do
es_client = Elasticsearch::Client.new log: true
# first delete the index
begin
es_client.indices.delete index: 'ribica'
rescue
Rails.logger.warn "Ribica index could not be deleted. Continuing with indexing operation..."
end
# now index items
all_items = Item.includes(sub_category: { category: :section }).all.to_a
all_items.each do |item|
es_client.index index: 'ribica', type: 'items', id: item.id, body: {
title: 'Test',
name: item.name,
code: item.code,
description: item.description,
sub_category: item.sub_category.name,
category: item.sub_category.category.name,
section: item.sub_category.category.section.name,
brand: item.brand.name
}
end
puts "ok!"
end
end