Fixed articles module.
This commit is contained in:
parent
f30e57dd49
commit
fc1c173718
14 changed files with 124 additions and 147 deletions
1
Gemfile
1
Gemfile
|
@ -18,7 +18,6 @@ end
|
||||||
gem 'jquery-rails'
|
gem 'jquery-rails'
|
||||||
|
|
||||||
gem 'mysql2'
|
gem 'mysql2'
|
||||||
gem "fastercsv"
|
|
||||||
gem 'prawn'
|
gem 'prawn'
|
||||||
gem 'haml-rails'
|
gem 'haml-rails'
|
||||||
gem 'kaminari'
|
gem 'kaminari'
|
||||||
|
|
|
@ -58,7 +58,6 @@ GEM
|
||||||
execjs (1.4.0)
|
execjs (1.4.0)
|
||||||
multi_json (~> 1.0)
|
multi_json (~> 1.0)
|
||||||
expression_parser (0.9.0)
|
expression_parser (0.9.0)
|
||||||
fastercsv (1.5.5)
|
|
||||||
haml (3.1.7)
|
haml (3.1.7)
|
||||||
haml-rails (0.3.5)
|
haml-rails (0.3.5)
|
||||||
actionpack (>= 3.1, < 4.1)
|
actionpack (>= 3.1, < 4.1)
|
||||||
|
@ -184,7 +183,6 @@ DEPENDENCIES
|
||||||
daemons
|
daemons
|
||||||
delayed_job_active_record
|
delayed_job_active_record
|
||||||
exception_notification
|
exception_notification
|
||||||
fastercsv
|
|
||||||
haml-rails
|
haml-rails
|
||||||
inherited_resources
|
inherited_resources
|
||||||
jquery-rails
|
jquery-rails
|
||||||
|
|
|
@ -46,8 +46,10 @@ $(function() {
|
||||||
// Submit form when changing a select menu.
|
// Submit form when changing a select menu.
|
||||||
$('form[data-submit-onchange] select').live('change', function() {
|
$('form[data-submit-onchange] select').live('change', function() {
|
||||||
var confirmMessage = $(this).children(':selected').data('confirm');
|
var confirmMessage = $(this).children(':selected').data('confirm');
|
||||||
if (confirmMessage && confirm(confirmMessage)) {
|
if (confirmMessage) {
|
||||||
|
if (confirm(confirmMessage)) {
|
||||||
$(this).parents('form').submit();
|
$(this).parents('form').submit();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$(this).parents('form').submit();
|
$(this).parents('form').submit();
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,3 +154,21 @@ tr.order-article .article-info {
|
||||||
tr.order-article:hover .article-info {
|
tr.order-article:hover .article-info {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ********* Articles
|
||||||
|
|
||||||
|
tr.just-updated {
|
||||||
|
color: #468847;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.unavailable {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
// articles edit all
|
||||||
|
.field_with_errors {
|
||||||
|
input, select {
|
||||||
|
border-color: red;
|
||||||
|
}
|
||||||
|
}
|
|
@ -76,34 +76,36 @@ class ArticlesController < ApplicationController
|
||||||
# Updates all article of specific supplier
|
# Updates all article of specific supplier
|
||||||
# deletes all articles from params[outlisted_articles]
|
# deletes all articles from params[outlisted_articles]
|
||||||
def update_all
|
def update_all
|
||||||
currentArticle = nil # used to find out which article caused a validation exception
|
|
||||||
begin
|
begin
|
||||||
Article.transaction do
|
Article.transaction do
|
||||||
unless params[:articles].blank?
|
unless params[:articles].blank?
|
||||||
|
invalid_articles = false
|
||||||
# Update other article attributes...
|
# Update other article attributes...
|
||||||
for id, attributes in params[:articles]
|
@articles = Article.find(params[:articles].keys)
|
||||||
currentArticle = Article.find(id)
|
@articles.each do |article|
|
||||||
currentArticle.update_attributes!(attributes)
|
unless article.update_attributes(params[:articles][article.id.to_s])
|
||||||
|
invalid_articles = true unless invalid_articles # Remember that there are validation errors
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
raise "Artikel sind fehlerhaft. Bitte überprüfe Deine Eingaben." if invalid_articles
|
||||||
|
end
|
||||||
# delete articles
|
# delete articles
|
||||||
if params[:outlisted_articles]
|
if params[:outlisted_articles]
|
||||||
params[:outlisted_articles].keys.each {|id| Article.find(id).destroy }
|
params[:outlisted_articles].keys.each {|id| Article.find(id).destroy }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
# Successfully done.
|
# Successfully done.
|
||||||
flash[:notice] = 'Alle Artikel und Preise wurden aktalisiert'
|
redirect_to supplier_articles_path(@supplier), notice: "Alle Artikel und Preise wurden aktalisiert"
|
||||||
redirect_to supplier_articles_path(@supplier)
|
|
||||||
|
|
||||||
rescue => e
|
rescue => e
|
||||||
# An error has occurred, transaction has been rolled back.
|
# An error has occurred, transaction has been rolled back.
|
||||||
if currentArticle
|
if params[:sync]
|
||||||
@failedArticle = currentArticle
|
flash[:error] = "Es trat ein Fehler beim Aktualisieren des Artikels '#{current_article.name}' auf: #{e.message}"
|
||||||
flash[:error] = "Es trat ein Fehler beim Aktualisieren des Artikels '#{currentArticle.name}' auf: #{e.message}"
|
redirect_to(supplier_articles_path(@supplier))
|
||||||
params[:sync] ? redirect_to(supplier_articles_path(@supplier)) : render(:action => 'edit_all')
|
|
||||||
else
|
else
|
||||||
flash[:error] = "Es trat ein Fehler beim Aktualisieren der Artikel auf: #{e.message}"
|
flash.now.alert = e.message
|
||||||
redirect_to supplier_articles_path(@supplier)
|
render :edit_all
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -178,17 +180,22 @@ class ArticlesController < ApplicationController
|
||||||
def create_from_upload
|
def create_from_upload
|
||||||
begin
|
begin
|
||||||
Article.transaction do
|
Article.transaction do
|
||||||
for article_attributes in params[:articles]
|
invalid_articles = false
|
||||||
@supplier.articles.create!(article_attributes)
|
@articles = []
|
||||||
|
params[:articles].each do |_key, article_attributes|
|
||||||
|
@articles << (article = @supplier.articles.build(article_attributes))
|
||||||
|
invalid_articles = true unless article.save
|
||||||
end
|
end
|
||||||
|
|
||||||
|
raise "Artikel sind fehlerhaft" if invalid_articles
|
||||||
end
|
end
|
||||||
# Successfully done.
|
# Successfully done.
|
||||||
flash[:notice] = "The articles are saved successfully"
|
redirect_to supplier_articles_path(@supplier), notice: "Es wurden #{@articles.size} neue Artikel gespeichert."
|
||||||
redirect_to supplier_articles_path(@supplier)
|
|
||||||
rescue => error
|
rescue => error
|
||||||
# An error has occurred, transaction has been rolled back.
|
# An error has occurred, transaction has been rolled back.
|
||||||
flash[:error] = "An error occured: #{error.message}"
|
flash.now[:error] = "An error occured: #{error.message}"
|
||||||
redirect_to upload_supplier_articles_path(@supplier)
|
render :parse_upload
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,10 @@ module ArticlesHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
def row_classes(article)
|
def row_classes(article)
|
||||||
classes = " "
|
classes = []
|
||||||
classes += " unavailable" if !article.availability
|
classes << "unavailable" if !article.availability
|
||||||
classes += " just_updated" if article.recently_updated && article.availability
|
classes << "just-updated" if article.recently_updated && article.availability
|
||||||
classes
|
classes.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
# Flatten search params, used in import from external database
|
# Flatten search params, used in import from external database
|
||||||
|
|
|
@ -15,7 +15,7 @@ class Article < ActiveRecord::Base
|
||||||
scope :not_in_stock, :conditions => {:type => nil}
|
scope :not_in_stock, :conditions => {:type => nil}
|
||||||
|
|
||||||
# Validations
|
# Validations
|
||||||
validates_presence_of :name, :unit, :price, :tax, :deposit, :unit_quantity, :supplier_id, :article_category_id
|
validates_presence_of :name, :unit, :price, :tax, :deposit, :unit_quantity, :supplier_id, :article_category
|
||||||
validates_length_of :name, :in => 4..60
|
validates_length_of :name, :in => 4..60
|
||||||
validates_length_of :unit, :in => 2..15
|
validates_length_of :unit, :in => 2..15
|
||||||
validates_numericality_of :price, :unit_quantity, :greater_than => 0
|
validates_numericality_of :price, :unit_quantity, :greater_than => 0
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
%tr{ :class => cycle('even','odd') + row_classes(article)}[article]
|
%tr{class: row_classes(article)}
|
||||||
%td= check_box_tag 'selected_articles[]', article.id.to_s, false, {:id => "checkbox_#{article.id}", 'data-ignore-onchange' => true}
|
%td= check_box_tag 'selected_articles[]', article.id.to_s, false, {:id => "checkbox_#{article.id}", 'data-ignore-onchange' => true}
|
||||||
%td{'data-check-this' => "#checkbox_#{article.id}", :class => 'click-me'}= article.name
|
%td{'data-check-this' => "#checkbox_#{article.id}", :class => 'click-me'}= article.name
|
||||||
%td= article.origin
|
%td= article.origin
|
||||||
|
@ -11,10 +11,9 @@
|
||||||
= number_to_currency(article.price)
|
= number_to_currency(article.price)
|
||||||
%td= number_to_percentage(article.tax) if article.tax != 0
|
%td= number_to_percentage(article.tax) if article.tax != 0
|
||||||
%td= number_to_currency(article.deposit) if article.deposit != 0
|
%td= number_to_currency(article.deposit) if article.deposit != 0
|
||||||
%td
|
%td= link_to "Bearbeiten", edit_supplier_article_path(@supplier, article),
|
||||||
= link_to icon(:edit), edit_supplier_article_path(@supplier, article),
|
:remote => true, class: 'btn btn-mini'
|
||||||
:remote => true
|
%td= link_to "Löschen", [@supplier, article],
|
||||||
= link_to icon(:delete), [@supplier, article],
|
:method => :delete, :confirm => 'Bist du sicher?', :remote => true, class: 'btn btn-mini btn-danger'
|
||||||
:method => :delete, :confirm => 'Bist du sicher?', :remote => true
|
|
||||||
|
|
||||||
|
|
34
app/views/articles/_edit_all_table.html.haml
Normal file
34
app/views/articles/_edit_all_table.html.haml
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
%table.table
|
||||||
|
%thead
|
||||||
|
%tr
|
||||||
|
%th
|
||||||
|
%acronym{:title => "verfügbar"} verf.
|
||||||
|
%th Name
|
||||||
|
%th Einheit
|
||||||
|
%th
|
||||||
|
%acronym{:title => "Netto!"} Preis
|
||||||
|
%th
|
||||||
|
%acronym{:title => "Gebindegröße"} GebGr
|
||||||
|
%th Best.Nr.
|
||||||
|
%th Notiz
|
||||||
|
%th Kategorie
|
||||||
|
%th MwSt.
|
||||||
|
%th Pfand
|
||||||
|
%tbody
|
||||||
|
- @articles.each_with_index do |article, index|
|
||||||
|
= fields_for "articles[#{article.id || index}]", article do |form|
|
||||||
|
%tr
|
||||||
|
%td= form.check_box 'availability'
|
||||||
|
%td= form.text_field 'name', class: 'input-medium'
|
||||||
|
%td= form.text_field 'unit', class: 'input-mini'
|
||||||
|
%td= form.text_field 'price', class: 'input-mini'
|
||||||
|
%td= form.text_field 'unit_quantity', class: 'input-mini'
|
||||||
|
%td= form.text_field 'order_number', class: 'input-mini'
|
||||||
|
%td= form.text_field 'note', class: 'input-medium'
|
||||||
|
%td= form.collection_select 'article_category_id', ArticleCategory.all,
|
||||||
|
:id, :name, { :include_blank => true }, class: 'input-small'
|
||||||
|
%td= form.text_field 'tax', class: 'input-mini'
|
||||||
|
%td= form.text_field 'deposit', class: 'input-mini'
|
||||||
|
- unless article.errors.empty?
|
||||||
|
%tr.alert
|
||||||
|
%td(colspan="10")= article.errors.full_messages.join(", ")
|
|
@ -1,62 +0,0 @@
|
||||||
<% title "Alle Artikel von #{@supplier.name} bearbeiten" %>
|
|
||||||
|
|
||||||
<div class="single_column" style="width:100%">
|
|
||||||
<div id="change_supplier">
|
|
||||||
<%= select_tag :switch_supplier,
|
|
||||||
options_for_select( Supplier.all.collect {|s| [s.name, edit_all_supplier_articles_url(s)] },
|
|
||||||
edit_all_supplier_articles_url(@supplier)),
|
|
||||||
'data-redirect-to' => true,
|
|
||||||
:style => "font-size: 0.9em;margin-left:1em;" %>
|
|
||||||
</div>
|
|
||||||
<div class="box_title">
|
|
||||||
<h2></h2>
|
|
||||||
</div>
|
|
||||||
<div class="box column_content">
|
|
||||||
<div id="links"><%= link_to 'zurück zur Liste', supplier_articles_path(@supplier) -%></div>
|
|
||||||
<p>
|
|
||||||
<i>
|
|
||||||
Pflichtfelder sind: Name, Einheit, (netto) Preis und Bestellnummer.
|
|
||||||
</i>
|
|
||||||
</p>
|
|
||||||
<%= form_tag(update_all_supplier_articles_path(@supplier)) do %>
|
|
||||||
<table id="articles_table" class="list">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th><acronym title="verfügbar">verf.</acronym></th>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Einheit</th>
|
|
||||||
<th><acronym title="Netto!">Preis</acronym></th>
|
|
||||||
<th><acronym title="Gebindegröße">GebGr</acronym></th>
|
|
||||||
<th>Best.Nr.</th>
|
|
||||||
<th>Notiz</th>
|
|
||||||
<th>Kategorie</th>
|
|
||||||
<th>MwSt.</th>
|
|
||||||
<th>Pfand</th>
|
|
||||||
</tr>
|
|
||||||
<tbody>
|
|
||||||
<% for article in @articles %>
|
|
||||||
<%= fields_for 'articles[]', article do |form| %>
|
|
||||||
<tr class="<%= cycle('even', 'odd') %>"<%= ' style="background-color: yellow"' if @failedArticle == article %>>
|
|
||||||
<td colspan="2">
|
|
||||||
<%= form.check_box 'availability' -%>
|
|
||||||
<%= form.text_field 'name', :size => 0 -%>
|
|
||||||
</td>
|
|
||||||
<td><%= form.text_field 'unit', :size => 5 -%></td>
|
|
||||||
<td><%= form.text_field 'price', :size => 4 -%></td>
|
|
||||||
<td><%= form.text_field 'unit_quantity', :size => 4 -%></td>
|
|
||||||
<td><%= form.text_field 'order_number', :size => 6 -%></td>
|
|
||||||
<td><%= form.text_field 'note', :size => 15 -%></td>
|
|
||||||
<td><%= form.select 'article_category_id', ArticleCategory.find(:all).collect {|a| [ a.name, a.id ] }, { :include_blank => true } -%></td>
|
|
||||||
<td><%= form.text_field 'tax', :size => 4 -%></td>
|
|
||||||
<td><%= form.text_field 'deposit', :size => 4 -%></td>
|
|
||||||
</tr>
|
|
||||||
<% end %>
|
|
||||||
<% end %>
|
|
||||||
<!--[eoform:article]-->
|
|
||||||
</tbody>
|
|
||||||
</table><br />
|
|
||||||
<i>Achtung, alle Artikel werden aktualisiert!</i><br />
|
|
||||||
<%= submit_tag 'Alle Artikel aktualisieren'%> | <%= link_to 'Abbrechen', supplier_articles_path(@supplier) %>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
11
app/views/articles/edit_all.html.haml
Normal file
11
app/views/articles/edit_all.html.haml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
- title "Alle Artikel von #{@supplier.name} bearbeiten" |
|
||||||
|
%p
|
||||||
|
%i
|
||||||
|
Pflichtfelder sind: Name, Einheit, (netto) Preis und Bestellnummer.
|
||||||
|
= form_tag(update_all_supplier_articles_path(@supplier)) do
|
||||||
|
= render 'edit_all_table'
|
||||||
|
%br/
|
||||||
|
%i Achtung, alle Artikel werden aktualisiert!
|
||||||
|
.form-actions
|
||||||
|
= submit_tag 'Alle Artikel aktualisieren', class: 'btn btn-primary'
|
||||||
|
= link_to 'oder abbrechen', supplier_articles_path(@supplier)
|
|
@ -6,35 +6,8 @@
|
||||||
Achtung, momentan gibt es keine Überprüfung auf doppelte Artikel.
|
Achtung, momentan gibt es keine Überprüfung auf doppelte Artikel.
|
||||||
|
|
||||||
= form_tag(create_from_upload_supplier_articles_path(@supplier)) do
|
= form_tag(create_from_upload_supplier_articles_path(@supplier)) do
|
||||||
%table
|
= render 'edit_all_table'
|
||||||
%tr
|
.form-actions
|
||||||
%th Nummer
|
= submit_tag "Speichere neue Artikel für #{@supplier.name}", class: 'btn btn-primary'
|
||||||
%th Name
|
= link_to "order abbrechen", upload_supplier_articles_path(@supplier)
|
||||||
%th Notiz
|
|
||||||
%th Hersteller
|
|
||||||
%th Herkunft
|
|
||||||
%th Einheit
|
|
||||||
%th Nettopreis
|
|
||||||
%th MwSt
|
|
||||||
%th Pfand
|
|
||||||
%th Gebindegröße
|
|
||||||
%th Kategorie
|
|
||||||
- for article in @articles
|
|
||||||
= fields_for "articles[]", article do |form|
|
|
||||||
%tr{:class => cycle('even', 'odd')}
|
|
||||||
%td= form.text_field 'order_number', :size => 6
|
|
||||||
%td= form.text_field 'name', :size => 0
|
|
||||||
%td= form.text_field 'note', :size => 15
|
|
||||||
%td= form.text_field 'manufacturer', :size => 6
|
|
||||||
%td= form.text_field 'origin', :size => 6
|
|
||||||
%td= form.text_field 'unit', :size => 5
|
|
||||||
%td= form.text_field 'price', :size => 4
|
|
||||||
%td= form.text_field 'tax', :size => 4
|
|
||||||
%td= form.text_field 'deposit', :size => 4
|
|
||||||
%td= form.text_field 'unit_quantity', :size => 4
|
|
||||||
%td= form.select 'article_category_id', ArticleCategory.find(:all).collect {|a| [ a.name, a.id ] }
|
|
||||||
%p
|
|
||||||
= submit_tag "Speichere neue Artikel für #{@supplier.name}"
|
|
||||||
|
|
|
||||||
= link_to "Zurück", upload_supplier_articles_path(@supplier)
|
|
||||||
|
|
|
@ -1,23 +1,21 @@
|
||||||
- title "#{@supplier.name} / Artikel hochladen"
|
- title "#{@supplier.name} / Artikel hochladen"
|
||||||
%p
|
%p
|
||||||
%i
|
|
||||||
Die Datei muss eine Textdatei mit der Endung '.csv' sein. Die erste Zeile
|
Die Datei muss eine Textdatei mit der Endung '.csv' sein. Die erste Zeile
|
||||||
wird beim Einlesen ignoriert.
|
wird beim Einlesen ignoriert.
|
||||||
%br/
|
%br/
|
||||||
Die Felder müssen mit einem Semikolon (';') getrennt und der Text mit doppelten
|
Die Felder müssen mit einem Semikolon (';') getrennt und der Text mit doppelten
|
||||||
Anführungszeichen ("Text...") umklammert werden.
|
Anführungszeichen ("Text...") umklammert werden.
|
||||||
%br/
|
%br/
|
||||||
Als Zeichensatz wird UTF-8 erwartet.
|
Als Zeichensatz wird UTF-8 erwartet. Korrekte Reihenfolge der Spalten:
|
||||||
%p
|
%pre
|
||||||
%i
|
|
||||||
Korrekte Reihenfolge der Spalten:
|
|
||||||
%br/
|
|
||||||
= ["Status (x=ausgelistet)", "Bestellnummer", "Name", "Notiz", "Hersteller", "Herkunft",
|
= ["Status (x=ausgelistet)", "Bestellnummer", "Name", "Notiz", "Hersteller", "Herkunft",
|
||||||
"Einheit", "Preis(netto)", "MwSt", "Pfand", "Gebindegröße",
|
"Einheit", "Preis(netto)", "MwSt", "Pfand", "Gebindegröße",
|
||||||
"Staffelmenge", "Staffelpreis", "Kategorie"].join(" | ")
|
"Staffelmenge", "Staffelpreis", "Kategorie"].join(" | ")
|
||||||
|
|
||||||
#uploadArticles.uploadForm
|
|
||||||
= form_for :articles, :url => parse_upload_supplier_articles_path(@supplier),
|
= form_for :articles, :url => parse_upload_supplier_articles_path(@supplier),
|
||||||
:html => { :multipart => true } do |form|
|
:html => { :multipart => true } do |f|
|
||||||
%p= form.file_field "file"
|
%label(for="articles_file")
|
||||||
%p= submit_tag "Datei hochladen"
|
Bitte wähle eine kompatible Datei aus
|
||||||
|
= f.file_field "file"
|
||||||
|
.form-actions
|
||||||
|
= submit_tag "Datei hochladen", class: 'btn'
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# Module for FoodSoft-File import
|
# Module for FoodSoft-File import
|
||||||
# The FoodSoft-File is a cvs-file, with semicolon-seperatet columns
|
# The FoodSoft-File is a cvs-file, with semicolon-seperatet columns
|
||||||
|
|
||||||
require 'faster_csv'
|
require 'csv'
|
||||||
|
|
||||||
module FoodsoftFile
|
module FoodsoftFile
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ module FoodsoftFile
|
||||||
def self.parse(file)
|
def self.parse(file)
|
||||||
articles, outlisted_articles = Array.new, Array.new
|
articles, outlisted_articles = Array.new, Array.new
|
||||||
row_index = 2
|
row_index = 2
|
||||||
FasterCSV.parse(file.read, {:col_sep => ";", :headers => true}) do |row|
|
::CSV.parse(file.read, {:col_sep => ";", :headers => true}) do |row|
|
||||||
# check if the line is empty
|
# check if the line is empty
|
||||||
unless row[2] == "" || row[2].nil?
|
unless row[2] == "" || row[2].nil?
|
||||||
article = {:number => row[1],
|
article = {:number => row[1],
|
||||||
|
|
Loading…
Reference in a new issue