added ribica rake task (item import, copying sections to menu etc.)
This commit is contained in:
@@ -4,6 +4,7 @@ class Item < ActiveRecord::Base
|
|||||||
belongs_to :sub_category
|
belongs_to :sub_category
|
||||||
belongs_to :supplier
|
belongs_to :supplier
|
||||||
belongs_to :brand
|
belongs_to :brand
|
||||||
|
belongs_to :delivery_time_estimation
|
||||||
has_and_belongs_to_many :item_groups, :join_table => 'item_item_groups'
|
has_and_belongs_to_many :item_groups, :join_table => 'item_item_groups'
|
||||||
|
|
||||||
validates_presence_of :name, :description, :list_price, :current_input_price, :tags, :unit_id, :code, :sub_category_id, :weight, :supplier_id
|
validates_presence_of :name, :description, :list_price, :current_input_price, :tags, :unit_id, :code, :sub_category_id, :weight, :supplier_id
|
||||||
@@ -12,13 +13,13 @@ class Item < ActiveRecord::Base
|
|||||||
# todo build a front end in backoffice (rails)
|
# todo build a front end in backoffice (rails)
|
||||||
def self.items_to_order
|
def self.items_to_order
|
||||||
return Item.find_by_sql(%Q{
|
return Item.find_by_sql(%Q{
|
||||||
select s.name as supplier, i.name as item, sum(iic.count) amount, i.current_input_price
|
select s.name as supplier, i.name as item, sum(iic.count) amount, i.current_input_price
|
||||||
from carts c
|
from carts c
|
||||||
join item_in_carts iic on iic.cart_id = c.id
|
join item_in_carts iic on iic.cart_id = c.id
|
||||||
join items i on i.id = iic.item_id
|
join items i on i.id = iic.item_id
|
||||||
join suppliers s on i.supplier_id = s.id
|
join suppliers s on i.supplier_id = s.id
|
||||||
where c.confirmed and not (c.packed or c.delivered)
|
where c.confirmed and not (c.packed or c.delivered)
|
||||||
group by s.name, i.name, i.current_input_price
|
group by s.name, i.name, i.current_input_price
|
||||||
order by s.name, amount desc;
|
order by s.name, amount desc;
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|||||||
309
back-office/lib/tasks/ribica.rake
Normal file
309
back-office/lib/tasks/ribica.rake
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
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
|
||||||
|
mmd.url = part
|
||||||
|
item.multi_media_descriptions << mmd
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def import_single_item(row, index, logger)
|
||||||
|
succes = true
|
||||||
|
begin
|
||||||
|
lookup = get_column_lookup
|
||||||
|
item = Item.new
|
||||||
|
item.name = row[lookup[:name_on_ribica]]
|
||||||
|
item.code = row[lookup[:code]]
|
||||||
|
item.current_input_price = row[lookup[:current_input_price]] || 11.00
|
||||||
|
item.list_price = row[lookup[:list_price]] || 12.00
|
||||||
|
item.units_in_pack = row[lookup[:units_in_pack]]
|
||||||
|
item.description = row[lookup[:description]] || "default description"
|
||||||
|
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}"
|
||||||
|
success = false
|
||||||
|
end
|
||||||
|
|
||||||
|
success
|
||||||
|
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"
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
lookup = get_column_lookup
|
||||||
|
path = Rails.root.join(input_file)
|
||||||
|
|
||||||
|
log_filename = "import.log"
|
||||||
|
log_filename = "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
|
||||||
|
if import_single_item(row, i, logger) == false
|
||||||
|
should_rollback = true
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
i += 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if validate_only || should_rollback
|
||||||
|
if should_rollback
|
||||||
|
logger.info "Rolling back because of errors"
|
||||||
|
end
|
||||||
|
|
||||||
|
raise ActiveRecord::Rollback
|
||||||
|
end
|
||||||
|
end
|
||||||
|
rescue Exception => e
|
||||||
|
logger.error "Error while importing: #{e}"
|
||||||
|
end
|
||||||
|
logger.info "Import done"
|
||||||
|
end
|
||||||
|
|
||||||
|
namespace :ribica do
|
||||||
|
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
|
||||||
|
end
|
||||||
|
mi.save!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
namespace :ribica do
|
||||||
|
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
|
||||||
|
task validate_items: :environment do
|
||||||
|
do_import true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
namespace :ribica do
|
||||||
|
task import_items: :environment do
|
||||||
|
do_import false
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
class ChangeCodeColumnOnItemsTable < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
change_column :items, :code, :string, limit: 30
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 20150328132019) do
|
ActiveRecord::Schema.define(version: 20150404114006) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
@@ -113,7 +113,7 @@ ActiveRecord::Schema.define(version: 20150328132019) do
|
|||||||
|
|
||||||
create_table "items", force: :cascade do |t|
|
create_table "items", force: :cascade do |t|
|
||||||
t.string "name"
|
t.string "name"
|
||||||
t.string "code", limit: 10
|
t.string "code", limit: 30
|
||||||
t.decimal "current_input_price", precision: 5, scale: 2
|
t.decimal "current_input_price", precision: 5, scale: 2
|
||||||
t.decimal "list_price", precision: 5, scale: 2
|
t.decimal "list_price", precision: 5, scale: 2
|
||||||
t.integer "unit_id"
|
t.integer "unit_id"
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
var React = require('react'),
|
var React = require('react'),
|
||||||
MenuItemListComponent = require('./shared/menuItemListComponent'),
|
MenuItemListComponent = require('./shared/menuItemListComponent'),
|
||||||
|
SectionListComponent = require('./shared/sectionsListComponent'),
|
||||||
|
|
||||||
Router = require('react-router'),
|
Router = require('react-router'),
|
||||||
Link = Router.Link,
|
Link = Router.Link,
|
||||||
RouteHandler = Router.RouteHandler,
|
RouteHandler = Router.RouteHandler,
|
||||||
@@ -14,7 +16,7 @@ var RootApp = React.createClass({
|
|||||||
|
|
||||||
// Add change listeners to stores
|
// Add change listeners to stores
|
||||||
componentDidMount: function() {
|
componentDidMount: function() {
|
||||||
InitializationStore.addChangeListener(this._onChange);
|
InitializationStore.addChangeListener(this._onChange);
|
||||||
InitializationActions.initialize();
|
InitializationActions.initialize();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -26,7 +28,7 @@ var RootApp = React.createClass({
|
|||||||
|
|
||||||
_onChange: function () {
|
_onChange: function () {
|
||||||
if (this.isMounted()) {
|
if (this.isMounted()) {
|
||||||
this.setState(InitializationStore.getState());
|
this.setState(InitializationStore.getState());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -44,7 +46,7 @@ var RootApp = React.createClass({
|
|||||||
<div className="container">
|
<div className="container">
|
||||||
<div className='page-header'>
|
<div className='page-header'>
|
||||||
<h1 className="main-heading">
|
<h1 className="main-heading">
|
||||||
|
|
||||||
<Link to="app"><img src="https://res.cloudinary.com/lfvt7ps2n/image/upload/c_scale,w_132/v1426226452/ribica-ispunjava-zelje_nng0gn.png" /></Link>
|
<Link to="app"><img src="https://res.cloudinary.com/lfvt7ps2n/image/upload/c_scale,w_132/v1426226452/ribica-ispunjava-zelje_nng0gn.png" /></Link>
|
||||||
|
|
||||||
</h1>
|
</h1>
|
||||||
@@ -68,9 +70,9 @@ var RootApp = React.createClass({
|
|||||||
<div className='row'>
|
<div className='row'>
|
||||||
<RouteHandler />
|
<RouteHandler />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user