Fixed articles module.

This commit is contained in:
benni 2012-10-28 18:03:50 +01:00
parent f30e57dd49
commit fc1c173718
14 changed files with 124 additions and 147 deletions

View file

@ -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'

View file

@ -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

View file

@ -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();
} }

View file

@ -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;
}
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View 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(", ")

View file

@ -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>

View 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)

View file

@ -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)

View file

@ -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'

View file

@ -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],