Merge remote-tracking branch 'upstream/master' into multiple-recurring-tasks

Conflicts:
	config/locales/de.yml
This commit is contained in:
Robert Waltemath 2013-06-12 10:00:11 +02:00
commit 46b07a6136
257 changed files with 5408 additions and 1931 deletions

21
Gemfile
View file

@ -11,22 +11,22 @@ group :assets do
gem 'coffee-rails', '~> 3.2.1' gem 'coffee-rails', '~> 3.2.1'
# See https://github.com/sstephenson/execjs#readme for more supported runtimes # See https://github.com/sstephenson/execjs#readme for more supported runtimes
gem 'therubyracer', :platforms => :ruby gem 'therubyracer', platforms: :ruby
gem 'uglifier', '>= 1.0.3' gem 'uglifier', '>= 1.0.3'
end end
gem 'jquery-rails' gem 'jquery-rails'
gem 'mysql2' gem 'mysql2'
gem 'prawn' gem 'prawn'
gem 'haml-rails' gem 'haml-rails'
gem 'kaminari' gem 'kaminari'
gem 'client_side_validations' gem 'client_side_validations'
gem 'simple_form' gem 'simple_form'
gem 'rails3_acts_as_paranoid', "~>0.2.0"
gem 'inherited_resources' gem 'inherited_resources'
gem 'localize_input', :git => "git://github.com/bennibu/localize_input.git" gem 'localize_input', git: "git://github.com/bennibu/localize_input.git"
gem 'wikicloth' gem 'wikicloth'
gem 'daemons' gem 'daemons'
gem 'twitter-bootstrap-rails' gem 'twitter-bootstrap-rails'
@ -37,14 +37,15 @@ gem 'acts_as_versioned', git: 'git://github.com/technoweenie/acts_as_versioned.g
gem 'acts_as_tree' gem 'acts_as_tree'
gem 'acts_as_configurable', git: 'git://github.com/bwalding/acts_as_configurable.git' gem 'acts_as_configurable', git: 'git://github.com/bwalding/acts_as_configurable.git'
gem 'resque' gem 'resque'
gem 'whenever', :require => false # For defining cronjobs, see config/schedule.rb gem 'whenever', require: false # For defining cronjobs, see config/schedule.rb
group :production do group :production do
gem 'exception_notification', :require => 'exception_notifier' gem 'exception_notification', require: 'exception_notifier'
end end
group :development do group :development do
gem 'sqlite3' gem 'sqlite3'
gem 'mailcatcher'
# Better error output # Better error output
gem 'better_errors' gem 'better_errors'
@ -56,4 +57,14 @@ group :development do
# Get infos when not using proper eager loading # Get infos when not using proper eager loading
gem 'bullet' gem 'bullet'
# Hide assets requests in log
gem 'quiet_assets'
# Deploy with Capistrano
gem 'capistrano', '2.13.5'
gem 'capistrano-ext'
#gem 'common_deploy', require: false, path: '../../common_deploy' # pending foodcoops/foodsoft#34, git: 'git://github.com/fsmanuel/common_deploy.git'
# Avoid having content-length warnings
gem 'thin'
end end

View file

@ -22,32 +22,32 @@ GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
Ascii85 (1.0.2) Ascii85 (1.0.2)
actionmailer (3.2.11) actionmailer (3.2.13)
actionpack (= 3.2.11) actionpack (= 3.2.13)
mail (~> 2.4.4) mail (~> 2.5.3)
actionpack (3.2.11) actionpack (3.2.13)
activemodel (= 3.2.11) activemodel (= 3.2.13)
activesupport (= 3.2.11) activesupport (= 3.2.13)
builder (~> 3.0.0) builder (~> 3.0.0)
erubis (~> 2.7.0) erubis (~> 2.7.0)
journey (~> 1.0.4) journey (~> 1.0.4)
rack (~> 1.4.0) rack (~> 1.4.5)
rack-cache (~> 1.2) rack-cache (~> 1.2)
rack-test (~> 0.6.1) rack-test (~> 0.6.1)
sprockets (~> 2.2.1) sprockets (~> 2.2.1)
activemodel (3.2.11) activemodel (3.2.13)
activesupport (= 3.2.11) activesupport (= 3.2.13)
builder (~> 3.0.0) builder (~> 3.0.0)
activerecord (3.2.11) activerecord (3.2.13)
activemodel (= 3.2.11) activemodel (= 3.2.13)
activesupport (= 3.2.11) activesupport (= 3.2.13)
arel (~> 3.0.2) arel (~> 3.0.2)
tzinfo (~> 0.3.29) tzinfo (~> 0.3.29)
activeresource (3.2.11) activeresource (3.2.13)
activemodel (= 3.2.11) activemodel (= 3.2.13)
activesupport (= 3.2.11) activesupport (= 3.2.13)
activesupport (3.2.11) activesupport (3.2.13)
i18n (~> 0.6) i18n (= 0.6.1)
multi_json (~> 1.0) multi_json (~> 1.0)
acts_as_tree (1.2.0) acts_as_tree (1.2.0)
activerecord (>= 3.0.0) activerecord (>= 3.0.0)
@ -59,6 +59,14 @@ GEM
builder (3.0.4) builder (3.0.4)
bullet (4.3.0) bullet (4.3.0)
uniform_notifier uniform_notifier
capistrano (2.13.5)
highline
net-scp (>= 1.0.0)
net-sftp (>= 2.0.0)
net-ssh (>= 2.0.14)
net-ssh-gateway (>= 1.1.0)
capistrano-ext (1.2.1)
capistrano (>= 1.0.0)
chronic (0.9.0) chronic (0.9.0)
client_side_validations (3.1.4) client_side_validations (3.1.4)
coderay (1.0.8) coderay (1.0.8)
@ -72,6 +80,7 @@ GEM
commonjs (0.2.6) commonjs (0.2.6)
daemons (1.1.9) daemons (1.1.9)
erubis (2.7.0) erubis (2.7.0)
eventmachine (1.0.3)
exception_notification (2.6.1) exception_notification (2.6.1)
actionmailer (>= 3.0.4) actionmailer (>= 3.0.4)
execjs (1.4.0) execjs (1.4.0)
@ -85,6 +94,7 @@ GEM
railties (>= 3.1, < 4.1) railties (>= 3.1, < 4.1)
has_scope (0.5.1) has_scope (0.5.1)
hashery (2.0.1) hashery (2.0.1)
highline (1.6.19)
hike (1.2.1) hike (1.2.1)
i18n (0.6.1) i18n (0.6.1)
inherited_resources (1.3.1) inherited_resources (1.3.1)
@ -94,7 +104,7 @@ GEM
jquery-rails (2.1.3) jquery-rails (2.1.3)
railties (>= 3.1.0, < 5.0) railties (>= 3.1.0, < 5.0)
thor (~> 0.14) thor (~> 0.14)
json (1.7.6) json (1.7.7)
kaminari (0.14.1) kaminari (0.14.1)
actionpack (>= 3.0.0) actionpack (>= 3.0.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
@ -104,18 +114,35 @@ GEM
actionpack (>= 3.1) actionpack (>= 3.1)
less (~> 2.2.0) less (~> 2.2.0)
libv8 (3.3.10.4) libv8 (3.3.10.4)
mail (2.4.4) mail (2.5.3)
i18n (>= 0.4.0) i18n (>= 0.4.0)
mime-types (~> 1.16) mime-types (~> 1.16)
treetop (~> 1.4.8) treetop (~> 1.4.8)
mailcatcher (0.5.11)
activesupport (~> 3.0)
eventmachine (~> 1.0.0)
haml (>= 3.1, < 5)
mail (~> 2.3)
sinatra (~> 1.2)
skinny (~> 0.2.3)
sqlite3 (~> 1.3)
thin (~> 1.5.0)
meta_search (1.1.3) meta_search (1.1.3)
actionpack (~> 3.1) actionpack (~> 3.1)
activerecord (~> 3.1) activerecord (~> 3.1)
activesupport (~> 3.1) activesupport (~> 3.1)
polyamorous (~> 0.5.0) polyamorous (~> 0.5.0)
mime-types (1.19) mime-types (1.21)
multi_json (1.5.0) mono_logger (1.1.0)
multi_json (1.7.3)
mysql2 (0.3.11) mysql2 (0.3.11)
net-scp (1.1.1)
net-ssh (>= 2.6.5)
net-sftp (2.1.2)
net-ssh (>= 2.6.5)
net-ssh (2.6.7)
net-ssh-gateway (1.2.0)
net-ssh (>= 2.6.5)
pdf-reader (1.2.0) pdf-reader (1.2.0)
Ascii85 (~> 1.0.0) Ascii85 (~> 1.0.0)
hashery (~> 2.0) hashery (~> 2.0)
@ -126,43 +153,44 @@ GEM
prawn (0.12.0) prawn (0.12.0)
pdf-reader (>= 0.9.0) pdf-reader (>= 0.9.0)
ttfunk (~> 1.0.2) ttfunk (~> 1.0.2)
rack (1.4.3) quiet_assets (1.0.2)
railties (>= 3.1, < 5.0)
rack (1.4.5)
rack-cache (1.2) rack-cache (1.2)
rack (>= 0.4) rack (>= 0.4)
rack-protection (1.3.2) rack-protection (1.5.0)
rack rack
rack-ssl (1.3.2) rack-ssl (1.3.3)
rack rack
rack-test (0.6.2) rack-test (0.6.2)
rack (>= 1.0) rack (>= 1.0)
rails (3.2.11) rails (3.2.13)
actionmailer (= 3.2.11) actionmailer (= 3.2.13)
actionpack (= 3.2.11) actionpack (= 3.2.13)
activerecord (= 3.2.11) activerecord (= 3.2.13)
activeresource (= 3.2.11) activeresource (= 3.2.13)
activesupport (= 3.2.11) activesupport (= 3.2.13)
bundler (~> 1.0) bundler (~> 1.0)
railties (= 3.2.11) railties (= 3.2.13)
rails3_acts_as_paranoid (0.2.4) railties (3.2.13)
activerecord (~> 3.2) actionpack (= 3.2.13)
railties (3.2.11) activesupport (= 3.2.13)
actionpack (= 3.2.11)
activesupport (= 3.2.11)
rack-ssl (~> 1.3.2) rack-ssl (~> 1.3.2)
rake (>= 0.8.7) rake (>= 0.8.7)
rdoc (~> 3.4) rdoc (~> 3.4)
thor (>= 0.14.6, < 2.0) thor (>= 0.14.6, < 2.0)
rake (10.0.3) rake (10.0.3)
rdoc (3.12) rdoc (3.12.2)
json (~> 1.4) json (~> 1.4)
redis (3.0.2) redis (3.0.4)
redis-namespace (1.2.1) redis-namespace (1.3.0)
redis (~> 3.0.0) redis (~> 3.0.0)
responders (0.9.3) responders (0.9.3)
railties (~> 3.1) railties (~> 3.1)
resque (1.23.0) resque (1.24.1)
mono_logger (~> 1.0)
multi_json (~> 1.0) multi_json (~> 1.0)
redis-namespace (~> 1.0) redis-namespace (~> 1.2)
sinatra (>= 0.9.2) sinatra (>= 0.9.2)
vegas (~> 0.1.2) vegas (~> 0.1.2)
ruby-prof (0.11.2) ruby-prof (0.11.2)
@ -179,10 +207,13 @@ GEM
simple_form (2.0.3) simple_form (2.0.3)
actionpack (~> 3.0) actionpack (~> 3.0)
activemodel (~> 3.0) activemodel (~> 3.0)
sinatra (1.3.3) sinatra (1.3.6)
rack (~> 1.3, >= 1.3.6) rack (~> 1.4)
rack-protection (~> 1.2) rack-protection (~> 1.3)
tilt (~> 1.3, >= 1.3.3) tilt (~> 1.3, >= 1.3.3)
skinny (0.2.3)
eventmachine (~> 1.0.0)
thin (~> 1.5.0)
sprockets (2.2.2) sprockets (2.2.2)
hike (~> 1.2) hike (~> 1.2)
multi_json (~> 1.0) multi_json (~> 1.0)
@ -192,8 +223,12 @@ GEM
test-unit (2.5.3) test-unit (2.5.3)
therubyracer (0.10.2) therubyracer (0.10.2)
libv8 (~> 3.3.10) libv8 (~> 3.3.10)
thor (0.16.0) thin (1.5.1)
tilt (1.3.3) daemons (>= 1.0.9)
eventmachine (>= 0.12.6)
rack (>= 1.0.0)
thor (0.17.0)
tilt (1.4.1)
treetop (1.4.12) treetop (1.4.12)
polyglot polyglot
polyglot (>= 0.3.1) polyglot (>= 0.3.1)
@ -203,7 +238,7 @@ GEM
less-rails (~> 2.2.3) less-rails (~> 2.2.3)
railties (>= 3.1) railties (>= 3.1)
therubyracer (~> 0.10.2) therubyracer (~> 0.10.2)
tzinfo (0.3.35) tzinfo (0.3.37)
uglifier (1.3.0) uglifier (1.3.0)
execjs (>= 0.3.0) execjs (>= 0.3.0)
multi_json (~> 1.0, >= 1.0.2) multi_json (~> 1.0, >= 1.0.2)
@ -227,6 +262,8 @@ DEPENDENCIES
better_errors better_errors
binding_of_caller binding_of_caller
bullet bullet
capistrano (= 2.13.5)
capistrano-ext
client_side_validations client_side_validations
coffee-rails (~> 3.2.1) coffee-rails (~> 3.2.1)
daemons daemons
@ -236,11 +273,12 @@ DEPENDENCIES
jquery-rails jquery-rails
kaminari kaminari
localize_input! localize_input!
mailcatcher
meta_search meta_search
mysql2 mysql2
prawn prawn
quiet_assets
rails (~> 3.2.9) rails (~> 3.2.9)
rails3_acts_as_paranoid (~> 0.2.0)
resque resque
ruby-prof ruby-prof
sass-rails (~> 3.2.3) sass-rails (~> 3.2.3)
@ -250,6 +288,7 @@ DEPENDENCIES
sqlite3 sqlite3
test-unit test-unit
therubyracer therubyracer
thin
twitter-bootstrap-rails twitter-bootstrap-rails
uglifier (>= 1.0.3) uglifier (>= 1.0.3)
whenever whenever

View file

@ -1,4 +0,0 @@
MULTI_COOP_INSTALL
------------------
TODO ...

View file

@ -1,17 +1,22 @@
== FoodSoft Important
--------
We changed the branch structure. The rails3 branch is now master. But you can safely send pull requests to rails3. It'll remain there for a couple of weeks.
FoodSoft
=========
Web-based software to manage a non-profit food coop (product catalog, ordering, accounting, job scheduling). Web-based software to manage a non-profit food coop (product catalog, ordering, accounting, job scheduling).
== Install More information about using this software and contributing can be found on the [wiki](https://github.com/foodcoops/foodsoft/wiki).
Have a look on README_DEVEL. Install
--------
Update, it is highly recommended to checkout the rails3 branch. As soon as possible I will merge this branch Have a look at [DEVELOPMENT](https://github.com/foodcoops/foodsoft/blob/master/doc/DEVELOPMENT) (possibly outdated) and the (more recent) [Developing](https://github.com/foodcoops/foodsoft/wiki/Developing) page on the wiki.
into master. So for beginnners, better start with the new (I hope much easier) code.
git checkout -b rails3 origin/rails3 License
-------
== License
FoodSoft - a webbased foodcoop management software FoodSoft - a webbased foodcoop management software
Copyright (C) 2011 Benni and Lasse Copyright (C) 2011 Benni and Lasse

View file

@ -35,11 +35,14 @@ $(function() {
// Check/Uncheck all checkboxes for a specific form // Check/Uncheck all checkboxes for a specific form
$('input[data-check-all]').live('click', function() { $('input[data-check-all]').live('click', function() {
var status = $(this).is(':checked') var status = $(this).is(':checked');
$($(this).data('check-all')).find('input[type="checkbox"]').each(function() { var context = $(this).data('check-all');
$(this).attr('checked', status); var elms = $('input[type="checkbox"]', context);
highlightRow($(this)); for(i=elms.length-1; i>=0; --i) { // performance can be an issue here, so use native loop
}); var elm = elms[i];
elm.checked = status;
highlightRow($(elm));
}
}); });
// Submit form when changing a select menu. // Submit form when changing a select menu.
@ -102,7 +105,7 @@ $(function() {
// gives the row an yellow background // gives the row an yellow background
function highlightRow(checkbox) { function highlightRow(checkbox) {
var row = checkbox.parents('tr'); var row = checkbox.closest('tr');
if (checkbox.is(':checked')) { if (checkbox.is(':checked')) {
row.addClass('selected'); row.addClass('selected');
} else { } else {

View file

@ -49,7 +49,7 @@ function addData(orderArticleId, itemPrice, itemUnit, itemSubtotal, itemQuantity
function increaseQuantity(item) { function increaseQuantity(item) {
var value = Number($('#q_' + item).val()) + 1; var value = Number($('#q_' + item).val()) + 1;
if (!isStockit || (value <= (quantityAvailable[item] - quantityOthers[item]))) { if (!isStockit || (value <= (quantityAvailable[item] + itemsAllocated[item]))) {
update(item, value, $('#t_' + item).val()); update(item, value, $('#t_' + item).val());
} }
} }

View file

@ -200,3 +200,11 @@ tr.unavailable {
border-color: red; border-color: red;
} }
} }
// ********* Tweaks & fixes
// need more space for supplier&order information (in German, at least)
.dl-horizontal {
dt { width: 160px; }
dd { margin-left: 170px; }
}

View file

@ -3,7 +3,7 @@ class Admin::OrdergroupsController < Admin::BaseController
inherit_resources inherit_resources
def index def index
@ordergroups = Ordergroup.order('name ASC') @ordergroups = Ordergroup.undeleted.order('name ASC')
# if somebody uses the search field: # if somebody uses the search field:
unless params[:query].blank? unless params[:query].blank?
@ -15,9 +15,9 @@ class Admin::OrdergroupsController < Admin::BaseController
def destroy def destroy
@ordergroup = Ordergroup.find(params[:id]) @ordergroup = Ordergroup.find(params[:id])
@ordergroup.destroy @ordergroup.mark_as_deleted
redirect_to admin_ordergroups_url, :notice => "Bestellgruppe wurde gelöscht" redirect_to admin_ordergroups_url, notice: t('admin.ordergroups.destroy.notice')
rescue => error rescue => error
redirect_to admin_ordergroups_url, :alert => "Bestellgruppe konnte nicht gelöscht werden: #{error}" redirect_to admin_ordergroups_url, alert: t('admin.ordergroups.destroy.error')
end end
end end

View file

@ -13,8 +13,8 @@ class Admin::WorkgroupsController < Admin::BaseController
def destroy def destroy
@workgroup = Workgroup.find(params[:id]) @workgroup = Workgroup.find(params[:id])
@workgroup.destroy @workgroup.destroy
redirect_to admin_workgroups_url, :notice => "Arbeitsgruppe wurde gelöscht" redirect_to admin_workgroups_url, notice: t('admin.workgroups.destroy.notice')
rescue => error rescue => error
redirect_to admin_workgroups_url, :alert => "Arbeitsgruppe konnte nicht gelöscht werden: #{error}" redirect_to admin_workgroups_url, alert: t('admin.workgroups.destroy.error')
end end
end end

View file

@ -5,17 +5,17 @@ class ArticleCategoriesController < ApplicationController
before_filter :authenticate_article_meta before_filter :authenticate_article_meta
def create def create
create!(:notice => "Die Kategorie wurde gespeichert") { article_categories_path } create!(:notice => I18n.t('article_categories.create.notice')) { article_categories_path }
end end
def update def update
update!(:notice => "Die Kategorie wurde aktualisiert") { article_categories_path } update!(:notice => I18n.t('article_categories.update.notice')) { article_categories_path }
end end
def destroy def destroy
destroy! destroy!
rescue => error rescue => error
redirect_to article_categories_path, alert: t('controller.article_categories.destroy.error', message: error.message) redirect_to article_categories_path, alert: I18n.t('article_categories.destroy.error', message: error.message)
end end
protected protected

View file

@ -20,7 +20,7 @@ class ArticlesController < ApplicationController
sort = "article_categories.name, articles.name" sort = "article_categories.name, articles.name"
end end
@articles = Article.where(supplier_id: @supplier, :type => nil).includes(:article_category).order(sort) @articles = Article.undeleted.where(supplier_id: @supplier, :type => nil).includes(:article_category).order(sort)
@articles = @articles.where('articles.name LIKE ?', "%#{params[:query]}%") unless params[:query].nil? @articles = @articles.where('articles.name LIKE ?', "%#{params[:query]}%") unless params[:query].nil?
@articles = @articles.page(params[:page]).per(@per_page) @articles = @articles.page(params[:page]).per(@per_page)
@ -64,22 +64,22 @@ class ArticlesController < ApplicationController
# Deletes article from database. send error msg, if article is used in a current order # Deletes article from database. send error msg, if article is used in a current order
def destroy def destroy
@article = Article.find(params[:id]) @article = Article.find(params[:id])
@article.destroy unless @order = @article.in_open_order # If article is in an active Order, the Order will be returned @article.mark_as_deleted unless @order = @article.in_open_order # If article is in an active Order, the Order will be returned
render :layout => false render :layout => false
end end
# Renders a form for editing all articles from a supplier # Renders a form for editing all articles from a supplier
def edit_all def edit_all
@articles = @supplier.articles @articles = @supplier.articles.undeleted
end end
# Updates all article of specific supplier # Updates all article of specific supplier
# deletes all articles from params[outlisted_articles]
def update_all def update_all
invalid_articles = false
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...
@articles = Article.find(params[:articles].keys) @articles = Article.find(params[:articles].keys)
@articles.each do |article| @articles.each do |article|
@ -88,52 +88,46 @@ class ArticlesController < ApplicationController
end end
end end
raise "Artikel sind fehlerhaft. Bitte überprüfe Deine Eingaben." if invalid_articles raise ActiveRecord::Rollback if invalid_articles # Rollback all changes
end end
# delete articles
if params[:outlisted_articles]
params[:outlisted_articles].keys.each {|id| Article.find(id).destroy }
end end
end end
# Successfully done.
redirect_to supplier_articles_path(@supplier), notice: "Alle Artikel und Preise wurden aktalisiert"
rescue => e if invalid_articles
# An error has occurred, transaction has been rolled back. # An error has occurred, transaction has been rolled back.
if params[:sync] flash.now.alert = I18n.t('articles.controller.error_invalid')
flash[:error] = "Es trat ein Fehler beim Aktualisieren des Artikels '#{current_article.name}' auf: #{e.message}"
redirect_to(supplier_articles_path(@supplier))
else
flash.now.alert = e.message
render :edit_all render :edit_all
end else
# Successfully done.
redirect_to supplier_articles_path(@supplier), notice: I18n.t('articles.controller.update_all.notice')
end end
end end
# makes different actions on selected articles # makes different actions on selected articles
def update_selected def update_selected
raise 'Du hast keine Artikel ausgewählt' if params[:selected_articles].nil? raise I18n.t('articles.controller.error_nosel') if params[:selected_articles].nil?
articles = Article.find(params[:selected_articles]) articles = Article.find(params[:selected_articles])
Article.transaction do
case params[:selected_action] case params[:selected_action]
when 'destroy' when 'destroy'
articles.each {|a| a.destroy } articles.each(&:mark_as_deleted)
flash[:notice] = 'Alle gewählten Artikel wurden gelöscht' flash[:notice] = I18n.t('articles.controller.update_sel.notice_destroy')
when 'setNotAvailable' when 'setNotAvailable'
articles.each {|a| a.update_attribute(:availability, false) } articles.each {|a| a.update_attribute(:availability, false) }
flash[:notice] = 'Alle gewählten Artikel wurden auf "nicht verfügbar" gesetzt' flash[:notice] = I18n.t('articles.controller.update_sel.notice_unavail')
when 'setAvailable' when 'setAvailable'
articles.each {|a| a.update_attribute(:availability, true) } articles.each {|a| a.update_attribute(:availability, true) }
flash[:notice] = 'Alle gewählten Artikel wurden auf "verfügbar" gesetzt' flash[:notice] = I18n.t('articles.controller.update_sel.notice_avail')
else else
flash[:alert] = 'Keine Aktion ausgewählt!' flash[:alert] = I18n.t('articles.controller.update_sel.notice_noaction')
end
end end
# action succeded # action succeded
redirect_to supplier_articles_url(@supplier, :per_page => params[:per_page]) redirect_to supplier_articles_url(@supplier, :per_page => params[:per_page])
rescue => error rescue => error
redirect_to supplier_articles_url(@supplier, :per_page => params[:per_page]), redirect_to supplier_articles_url(@supplier, :per_page => params[:per_page]),
:alert => "Ein Fehler ist aufgetreten: #{error}" :alert => I18n.t('errors.general_msg', :msg => error)
end end
# lets start with parsing articles from uploaded file, yeah # lets start with parsing articles from uploaded file, yeah
@ -166,13 +160,13 @@ class ArticlesController < ApplicationController
:tax => row[:tax]) :tax => row[:tax])
# stop parsing, when an article isn't valid # stop parsing, when an article isn't valid
unless article.valid? unless article.valid?
raise article.errors.full_messages.join(", ") + " ..in line " + (articles.index(row) + 2).to_s raise I18n.t('articles.controller.error_parse', :msg => article.errors.full_messages.join(", "), :line => (articles.index(row) + 2).to_s)
end end
@articles << article @articles << article
end end
flash.now[:notice] = "#{@articles.size} articles are parsed successfully." flash.now[:notice] = I18n.t('articles.controller.parse_upload.notice', :count => @articles.size)
rescue => error rescue => error
redirect_to upload_supplier_articles_path(@supplier), :alert => "An error has occurred: #{error.message}" redirect_to upload_supplier_articles_path(@supplier), :alert => I18n.t('errors.general_msg', :msg => error.message)
end end
end end
@ -187,14 +181,14 @@ class ArticlesController < ApplicationController
invalid_articles = true unless article.save invalid_articles = true unless article.save
end end
raise "Artikel sind fehlerhaft" if invalid_articles raise I18n.t('articles.controller.error_invalid') if invalid_articles
end end
# Successfully done. # Successfully done.
redirect_to supplier_articles_path(@supplier), notice: "Es wurden #{@articles.size} neue Artikel gespeichert." redirect_to supplier_articles_path(@supplier), notice: I18n.t('articles.controller.create_from_upload.notice', :count => @articles.size)
rescue => error rescue => error
# An error has occurred, transaction has been rolled back. # An error has occurred, transaction has been rolled back.
flash.now[:error] = "An error occured: #{error.message}" flash.now[:error] = I18n.t('errors.general_msg', :msg => error.message)
render :parse_upload render :parse_upload
end end
end end
@ -221,14 +215,43 @@ class ArticlesController < ApplicationController
def sync def sync
# check if there is an shared_supplier # check if there is an shared_supplier
unless @supplier.shared_supplier unless @supplier.shared_supplier
redirect_to supplier_articles_url(@supplier), :alert => "#{@supplier.name} ist nicht mit einer externen Datenbank verknüpft." redirect_to supplier_articles_url(@supplier), :alert => I18n.t('articles.controller.sync.shared_alert', :supplier => @supplier.name)
end end
# sync articles against external database # sync articles against external database
@updated_articles, @outlisted_articles = @supplier.sync_all @updated_articles, @outlisted_articles = @supplier.sync_all
# convert to db-compatible-string # convert to db-compatible-string
@updated_articles.each {|a, b| a.shared_updated_on = a.shared_updated_on.to_formatted_s(:db)} @updated_articles.each {|a, b| a.shared_updated_on = a.shared_updated_on.to_formatted_s(:db)}
if @updated_articles.empty? && @outlisted_articles.empty? if @updated_articles.empty? && @outlisted_articles.empty?
redirect_to supplier_articles_path(@supplier), :notice => "Der Katalog ist aktuell." redirect_to supplier_articles_path(@supplier), :notice => I18n.t('articles.controller.sync.notice')
end
end
# Updates, deletes articles when sync form is submitted
def update_synchronized
begin
Article.transaction do
# delete articles
if params[:outlisted_articles]
Article.find(params[:outlisted_articles].keys).each(&:mark_as_deleted)
end
# Update articles
params[:articles].each do |id, attrs|
Article.find(id).update_attributes! attrs
end
end
# Successfully done.
redirect_to supplier_articles_path(@supplier), notice: I18n.t('articles.controller.update_sync.notice')
rescue ActiveRecord::RecordInvalid => invalid
# An error has occurred, transaction has been rolled back.
redirect_to supplier_articles_path(@supplier),
alert: I18n.t('articles.controller.error_update', :article => invalid.record.name, :msg => invalid.record.errors.full_messages)
rescue => error
redirect_to supplier_articles_path(@supplier),
alert: I18n.t('errors.general_msg', :msg => error.message)
end end
end end
end end

View file

@ -35,7 +35,7 @@ class DeliveriesController < ApplicationController
respond_to do |format| respond_to do |format|
if @delivery.save if @delivery.save
flash[:notice] = 'Lieferung wurde erstellt. Bitte nicht vergessen die Rechnung anzulegen!' flash[:notice] = I18n.t('deliveries.create.notice')
format.html { redirect_to([@supplier,@delivery]) } format.html { redirect_to([@supplier,@delivery]) }
format.xml { render :xml => @delivery, :status => :created, :location => @delivery } format.xml { render :xml => @delivery, :status => :created, :location => @delivery }
else else
@ -54,7 +54,7 @@ class DeliveriesController < ApplicationController
respond_to do |format| respond_to do |format|
if @delivery.update_attributes(params[:delivery]) if @delivery.update_attributes(params[:delivery])
flash[:notice] = 'Lieferung wurde aktualisiert.' flash[:notice] = I18n.t('deliveries.update.notice')
format.html { redirect_to([@supplier,@delivery]) } format.html { redirect_to([@supplier,@delivery]) }
format.xml { head :ok } format.xml { head :ok }
else else
@ -68,7 +68,7 @@ class DeliveriesController < ApplicationController
@delivery = Delivery.find(params[:id]) @delivery = Delivery.find(params[:id])
@delivery.destroy @delivery.destroy
flash[:notice] = "Lieferung wurde gelöscht." flash[:notice] = I18n.t('deliveries.destroy.notice')
respond_to do |format| respond_to do |format|
format.html { redirect_to(supplier_deliveries_url(@supplier)) } format.html { redirect_to(supplier_deliveries_url(@supplier)) }
format.xml { head :ok } format.xml { head :ok }

View file

@ -6,7 +6,7 @@ class FeedbackController < ApplicationController
def create def create
if params[:message].present? if params[:message].present?
Mailer.feedback(current_user, params[:message]).deliver Mailer.feedback(current_user, params[:message]).deliver
redirect_to root_url, :notice => "Das Feedback wurde erfolgreich verschickt. Vielen Dank!" redirect_to root_url, notice: t('feedback.create.notice')
else else
render :action => 'new' render :action => 'new'
end end

View file

@ -7,10 +7,10 @@ class Finance::BalancingController < Finance::BaseController
def new def new
@order = Order.find(params[:order_id]) @order = Order.find(params[:order_id])
flash.now.alert = "Achtung, Bestellung wurde schon abgerechnet" if @order.closed? flash.now.alert = t('finance.balancing.new.alert') if @order.closed?
@comments = @order.comments @comments = @order.comments
@articles = @order.order_articles.ordered.includes(:order, :article_price, @articles = @order.order_articles.ordered.includes(:article, :article_price,
group_order_articles: {group_order: :ordergroup}) group_order_articles: {group_order: :ordergroup})
sort_param = params['sort'] || 'name' sort_param = params['sort'] || 'name'
@ -30,6 +30,10 @@ class Finance::BalancingController < Finance::BaseController
render layout: false if request.xhr? render layout: false if request.xhr?
end end
def update_summary
@order = Order.find(params[:id])
end
def edit_note def edit_note
@order = Order.find(params[:id]) @order = Order.find(params[:id])
render :layout => false render :layout => false
@ -53,19 +57,19 @@ class Finance::BalancingController < Finance::BaseController
def close def close
@order = Order.find(params[:id]) @order = Order.find(params[:id])
@order.close!(@current_user) @order.close!(@current_user)
redirect_to finance_root_url, notice: "Bestellung wurde erfolgreich abgerechnet, die Kontostände aktualisiert." redirect_to finance_order_index_url, notice: t('finance.balancing.close.notice')
rescue => error rescue => error
redirect_to new_finance_order_url(order_id: @order.id), alert: "Ein Fehler ist beim Abrechnen aufgetreten: #{error.message}" redirect_to new_finance_order_url(order_id: @order.id), alert: t('finance.balancing.close.alert', message: error.message)
end end
# Close the order directly, without automaticly updating ordergroups account balances # Close the order directly, without automaticly updating ordergroups account balances
def close_direct def close_direct
@order = Order.find(params[:id]) @order = Order.find(params[:id])
@order.close_direct!(@current_user) @order.close_direct!(@current_user)
redirect_to finance_balancing_url, notice: "Bestellung wurde geschlossen." redirect_to finance_order_index_url, notice: t('finance.balancing.close_direct.notice')
rescue => error rescue => error
redirect_to finance_balancing_url, alert: "Bestellung kann nicht geschlossen werden: #{error.message}" redirect_to finance_order_index_url, alert: t('finance.balancing.close_direct.alert', message: error.message)
end end
end end

View file

@ -34,7 +34,7 @@ class Finance::FinancialTransactionsController < ApplicationController
@financial_transaction = FinancialTransaction.new(params[:financial_transaction]) @financial_transaction = FinancialTransaction.new(params[:financial_transaction])
@financial_transaction.user = current_user @financial_transaction.user = current_user
@financial_transaction.add_transaction! @financial_transaction.add_transaction!
redirect_to finance_ordergroup_transactions_url(@ordergroup), :notice => "Die Transaktion wurde gespeichert." redirect_to finance_ordergroup_transactions_url(@ordergroup), notice: t('finance.financial_transactions.create.notice')
rescue ActiveRecord::RecordInvalid => error rescue ActiveRecord::RecordInvalid => error
flash.now[:alert] = error.message flash.now[:alert] = error.message
render :action => :new render :action => :new
@ -51,9 +51,9 @@ class Finance::FinancialTransactionsController < ApplicationController
Ordergroup.find(trans[:ordergroup_id]).add_financial_transaction!(trans[:amount], params[:note], @current_user) Ordergroup.find(trans[:ordergroup_id]).add_financial_transaction!(trans[:amount], params[:note], @current_user)
end end
end end
redirect_to finance_ordergroups_url, notice: "Alle Transaktionen wurden gespeichert." redirect_to finance_ordergroups_url, notice: t('finance.create_collection.create.notice')
rescue => error rescue => error
redirect_to finance_new_transaction_collection_url, alert: "Ein Fehler ist aufgetreten: " + error.to_s redirect_to finance_new_transaction_collection_url, alert: t('finance.create_collection.create.alert', error: error.to_s)
end end
protected protected

View file

@ -22,7 +22,7 @@ class Finance::InvoicesController < ApplicationController
@invoice = Invoice.new(params[:invoice]) @invoice = Invoice.new(params[:invoice])
if @invoice.save if @invoice.save
flash[:notice] = "Rechnung wurde erstellt." flash[:notice] = I18n.t('finance.create.notice')
if @invoice.order if @invoice.order
# Redirect to balancing page # Redirect to balancing page
redirect_to new_finance_order_url(order_id: @invoice.order.id) redirect_to new_finance_order_url(order_id: @invoice.order.id)
@ -38,7 +38,7 @@ class Finance::InvoicesController < ApplicationController
@invoice = Invoice.find(params[:id]) @invoice = Invoice.find(params[:id])
if @invoice.update_attributes(params[:invoice]) if @invoice.update_attributes(params[:invoice])
redirect_to [:finance, @invoice], notice: "Rechnung wurde aktualisiert." redirect_to [:finance, @invoice], notice: I18n.t('finance.update.notice')
else else
render :edit render :edit
end end

View file

@ -26,7 +26,7 @@ class Finance::OrderArticlesController < ApplicationController
@order = Order.find(params[:order_id]) @order = Order.find(params[:order_id])
@order_article = OrderArticle.find(params[:id]) @order_article = OrderArticle.find(params[:id])
begin begin
@order_article.update_article_and_price!(params[:article], params[:article_price], params[:order_article]) @order_article.update_article_and_price!(params[:order_article], params[:article], params[:article_price])
rescue rescue
render action: :edit render action: :edit
end end

View file

@ -12,7 +12,7 @@ class Finance::OrdergroupsController < Finance::BaseController
sort = "name" sort = "name"
end end
@ordergroups = Ordergroup.order(sort) @ordergroups = Ordergroup.undeleted.order(sort)
@ordergroups = @ordergroups.where('name LIKE ?', "%#{params[:query]}%") unless params[:query].nil? @ordergroups = @ordergroups.where('name LIKE ?', "%#{params[:query]}%") unless params[:query].nil?
@ordergroups = @ordergroups.page(params[:page]).per(@per_page) @ordergroups = @ordergroups.page(params[:page]).per(@per_page)

View file

@ -1,7 +1,7 @@
class Foodcoop::OrdergroupsController < ApplicationController class Foodcoop::OrdergroupsController < ApplicationController
def index def index
@ordergroups = Ordergroup.order('name DESC') @ordergroups = Ordergroup.undeleted.order('name DESC')
unless params[:name].blank? # Search by name unless params[:name].blank? # Search by name
@ordergroups = @ordergroups.where('name LIKE ?', "%#{params[:name]}%") @ordergroups = @ordergroups.where('name LIKE ?', "%#{params[:name]}%")

View file

@ -14,7 +14,7 @@ class Foodcoop::WorkgroupsController < ApplicationController
def update def update
@workgroup = Workgroup.find(params[:id]) @workgroup = Workgroup.find(params[:id])
if @workgroup.update_attributes(params[:workgroup]) if @workgroup.update_attributes(params[:workgroup])
redirect_to foodcoop_workgroups_url, :notice => "Arbeitsgruppe wurde aktualisiert" redirect_to foodcoop_workgroups_url, :notice => I18n.t('workgroups.update.notice')
else else
render :action => 'edit' render :action => 'edit'
end end

View file

@ -20,12 +20,12 @@ class GroupOrdersController < ApplicationController
@group_order = GroupOrder.new(params[:group_order]) @group_order = GroupOrder.new(params[:group_order])
begin begin
@group_order.save_ordering! @group_order.save_ordering!
redirect_to group_order_url(@group_order), :notice => 'Die Bestellung wurde gespeichert.' redirect_to group_order_url(@group_order), :notice => I18n.t('group_orders.create.notice')
rescue ActiveRecord::StaleObjectError rescue ActiveRecord::StaleObjectError
redirect_to group_orders_url, :alert => 'In der Zwischenzeit hat jemand anderes auch bestellt, daher konnte die Bestellung nicht aktualisiert werden.' redirect_to group_orders_url, :alert => I18n.t('group_orders.create.error_stale')
rescue => exception rescue => exception
logger.error('Failed to update order: ' + exception.message) logger.error('Failed to update order: ' + exception.message)
redirect_to group_orders_url, :alert => 'Die Bestellung konnte nicht aktualisiert werden, da ein Fehler auftrat.' redirect_to group_orders_url, :alert => I18n.t('group_orders.create.error_general')
end end
end end
@ -41,12 +41,12 @@ class GroupOrdersController < ApplicationController
@group_order.attributes = params[:group_order] @group_order.attributes = params[:group_order]
begin begin
@group_order.save_ordering! @group_order.save_ordering!
redirect_to group_order_url(@group_order), :notice => 'Die Bestellung wurde gespeichert.' redirect_to group_order_url(@group_order), :notice => I18n.t('group_orders.update.notice')
rescue ActiveRecord::StaleObjectError rescue ActiveRecord::StaleObjectError
redirect_to group_orders_url, :alert => 'In der Zwischenzeit hat jemand anderes auch bestellt, daher konnte die Bestellung nicht aktualisiert werden.' redirect_to group_orders_url, :alert => I18n.t('group_orders.update.error_stale')
rescue => exception rescue => exception
logger.error('Failed to update order: ' + exception.message) logger.error('Failed to update order: ' + exception.message)
redirect_to group_orders_url, :alert => 'Die Bestellung konnte nicht aktualisiert werden, da ein Fehler auftrat.' redirect_to group_orders_url, :alert => I18n.t('group_orders.update.error_general')
end end
end end
@ -69,7 +69,7 @@ class GroupOrdersController < ApplicationController
def ensure_ordergroup_member def ensure_ordergroup_member
@ordergroup = @current_user.ordergroup @ordergroup = @current_user.ordergroup
if @ordergroup.nil? if @ordergroup.nil?
redirect_to root_url, :alert => "Du bist kein Mitglieder einer Bestellgruppe." redirect_to root_url, :alert => I18n.t('group_orders.errors.no_member')
end end
end end
@ -77,7 +77,7 @@ class GroupOrdersController < ApplicationController
@order = Order.find((params[:order_id] || params[:group_order][:order_id]), @order = Order.find((params[:order_id] || params[:group_order][:order_id]),
:include => [:supplier, :order_articles]) :include => [:supplier, :order_articles])
unless @order.open? unless @order.open?
flash[:notice] = 'Diese Bestellung ist bereits abgeschlossen.' flash[:notice] = I18n.t('group_orders.error_closed')
redirect_to :action => 'index' redirect_to :action => 'index'
end end
end end
@ -85,7 +85,7 @@ class GroupOrdersController < ApplicationController
def ensure_my_group_order def ensure_my_group_order
@group_order = @ordergroup.group_orders.find(params[:id]) @group_order = @ordergroup.group_orders.find(params[:id])
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
redirect_to group_orders_url, alert: 'Fehlerhafte URL, das ist nicht Deine Bestellung.' redirect_to group_orders_url, alert: I18n.t('group_orders.errors.notfound')
end end
def enough_apples? def enough_apples?

View file

@ -16,7 +16,7 @@ class HomeController < ApplicationController
def update_profile def update_profile
if @current_user.update_attributes(params[:user]) if @current_user.update_attributes(params[:user])
redirect_to my_profile_url, notice: 'Änderungen wurden gespeichert.' redirect_to my_profile_url, notice: I18n.t('home.changes_saved')
else else
render :profile render :profile
end end
@ -45,7 +45,7 @@ class HomeController < ApplicationController
@financial_transactions = @financial_transactions.where("note LIKE ?", "%#{params[:query]}%") if params[:query].present? @financial_transactions = @financial_transactions.where("note LIKE ?", "%#{params[:query]}%") if params[:query].present?
else else
redirect_to root_path, :alert => "Leider bist Du kein Mitglied einer Bestellgruppe" redirect_to root_path, :alert => I18n.t('home.no_ordergroups')
end end
end end
@ -54,9 +54,9 @@ class HomeController < ApplicationController
membership = Membership.find(params[:membership_id]) membership = Membership.find(params[:membership_id])
if membership.user == current_user if membership.user == current_user
membership.destroy membership.destroy
flash[:notice] = "Du bist jetzt kein Mitglied der Gruppe #{membership.group.name} mehr." flash[:notice] = I18n.t('home.ordergroup_cancelled', :group => membership.group.name)
else else
flash[:error] = "Ein Problem ist aufgetreten." flash[:error] = I18n.t('errors.general')
end end
redirect_to my_profile_path redirect_to my_profile_path
end end

View file

@ -1,7 +1,7 @@
class InvitesController < ApplicationController class InvitesController < ApplicationController
before_filter :authenticate_membership_or_admin, :only => [:new] before_filter :authenticate_membership_or_admin, :only => [:new]
#TODO: auhtorize also for create action. #TODO: authorize also for create action.
def new def new
@invite = Invite.new(:user => @current_user, :group => @group) @invite = Invite.new(:user => @current_user, :group => @group)
@ -14,7 +14,7 @@ class InvitesController < ApplicationController
respond_to do |format| respond_to do |format|
format.html do format.html do
redirect_to back_or_default_path, notice: "Benutzerin wurde erfolgreich eingeladen." redirect_to back_or_default_path, notice: I18n.t('invites.success')
end end
format.js { render layout: false } format.js { render layout: false }
end end

View file

@ -10,6 +10,10 @@ class LoginController < ApplicationController
# Sends an email to a user with the token that allows setting a new password through action "password". # Sends an email to a user with the token that allows setting a new password through action "password".
def reset_password def reset_password
if request.get? || params[:user].nil? # Catch for get request and give better error message.
redirect_to forgot_password_url, alert: 'Ein Problem ist aufgetreten. Bitte erneut versuchen' and return
end
if (user = User.find_by_email(params[:user][:email])) if (user = User.find_by_email(params[:user][:email]))
user.reset_password_token = user.new_random_password(16) user.reset_password_token = user.new_random_password(16)
user.reset_password_expires = Time.now.advance(:days => 2) user.reset_password_expires = Time.now.advance(:days => 2)
@ -18,7 +22,7 @@ class LoginController < ApplicationController
logger.debug("Sent password reset email to #{user.email}.") logger.debug("Sent password reset email to #{user.email}.")
end end
end end
redirect_to login_url, :notice => "Wenn Deine E-Mail hier registiert ist bekommst Du jetzt eine Nachricht mit einem Passwort-Zurücksetzen-Link." redirect_to login_url, :notice => I18n.t('login.controller.reset_password.notice')
end end
# Set a new password with a token from the password reminder email. # Set a new password with a token from the password reminder email.
@ -34,7 +38,7 @@ class LoginController < ApplicationController
@user.reset_password_token = nil @user.reset_password_token = nil
@user.reset_password_expires = nil @user.reset_password_expires = nil
@user.save @user.save
redirect_to login_url, :notice => "Dein Passwort wurde aktualisiert. Du kannst Dich jetzt anmelden." redirect_to login_url, :notice => I18n.t('login.controller.update_password.notice')
else else
render :new_password render :new_password
end end
@ -43,27 +47,23 @@ class LoginController < ApplicationController
# For invited users. # For invited users.
def accept_invitation def accept_invitation
@invite = Invite.find_by_token(params[:token]) @invite = Invite.find_by_token(params[:token])
if (@invite.nil? || @invite.expires_at < Time.now) if @invite.nil? || @invite.expires_at < Time.now
flash[:error] = "Deine Einladung ist nicht (mehr) gültig." redirect_to login_url, alert: I18n.t('login.controller.error_invite_invalid')
render :action => 'login'
elsif @invite.group.nil? elsif @invite.group.nil?
flash[:error] = "Die Gruppe, in die Du eingeladen wurdest, existiert leider nicht mehr." redirect_to login_url, alert: I18n.t('login.controller.error_group_invalid')
render :action => 'login' elsif request.post?
elsif (request.post?)
User.transaction do User.transaction do
@user = User.new(params[:user]) @user = User.new(params[:user])
@user.email = @invite.email @user.email = @invite.email
if @user.save if @user.save
Membership.new(:user => @user, :group => @invite.group).save! Membership.new(:user => @user, :group => @invite.group).save!
@invite.destroy @invite.destroy
redirect_to login_url, notice: "Herzlichen Glückwunsch, Dein Account wurde erstellt. Du kannst Dich nun einloggen." redirect_to login_url, notice: I18n.t('login.controller.accept_invitation.notice')
end end
end end
else else
@user = User.new(:email => @invite.email) @user = User.new(:email => @invite.email)
end end
rescue
flash[:error] = "Ein Fehler ist aufgetreten. Bitte erneut versuchen."
end end
protected protected
@ -71,8 +71,7 @@ class LoginController < ApplicationController
def validate_token def validate_token
@user = User.find_by_id_and_reset_password_token(params[:id], params[:token]) @user = User.find_by_id_and_reset_password_token(params[:id], params[:token])
if (@user.nil? || @user.reset_password_expires < Time.now) if (@user.nil? || @user.reset_password_expires < Time.now)
flash.now.error = "Ungültiger oder abgelaufener Token. Bitte versuch es erneut." redirect_to forgot_password_url, alert: I18n.t('login.controller.error_token_invalid')
render :action => 'forgot_password'
end end
end end
end end

View file

@ -8,6 +8,9 @@ class MessagesController < ApplicationController
# Creates a new message object. # Creates a new message object.
def new def new
@message = Message.new(params[:message]) @message = Message.new(params[:message])
if @message.reply_to and not @message.reply_to.is_readable_for?(current_user)
redirect_to new_message_url, alert: 'Nachricht ist privat!'
end
end end
# Creates a new message. # Creates a new message.
@ -15,7 +18,7 @@ class MessagesController < ApplicationController
@message = @current_user.send_messages.new(params[:message]) @message = @current_user.send_messages.new(params[:message])
if @message.save if @message.save
Resque.enqueue(UserNotifier, FoodsoftConfig.scope, 'message_deliver', @message.id) Resque.enqueue(UserNotifier, FoodsoftConfig.scope, 'message_deliver', @message.id)
redirect_to messages_url, :notice => "Nachricht ist gespeichert und wird versendet." redirect_to messages_url, :notice => I18n.t('messages.create.notice')
else else
render :action => 'new' render :action => 'new'
end end
@ -24,5 +27,8 @@ class MessagesController < ApplicationController
# Shows a single message. # Shows a single message.
def show def show
@message = Message.find(params[:id]) @message = Message.find(params[:id])
unless @message.is_readable_for?(current_user)
redirect_to messages_url, alert: 'Nachricht ist privat!'
end
end end
end end

View file

@ -62,7 +62,7 @@ class OrdersController < ApplicationController
@order = Order.new(params[:order]) @order = Order.new(params[:order])
@order.created_by = current_user @order.created_by = current_user
if @order.save if @order.save
flash[:notice] = "Die Bestellung wurde erstellt." flash[:notice] = I18n.t('orders.create.notice')
redirect_to @order redirect_to @order
else else
logger.debug "[debug] order errors: #{@order.errors.messages}" logger.debug "[debug] order errors: #{@order.errors.messages}"
@ -80,7 +80,7 @@ class OrdersController < ApplicationController
def update def update
@order = Order.find params[:id] @order = Order.find params[:id]
if @order.update_attributes params[:order] if @order.update_attributes params[:order]
flash[:notice] = "Die Bestellung wurde aktualisiert." flash[:notice] = I18n.t('orders.update.notice')
redirect_to :action => 'show', :id => @order redirect_to :action => 'show', :id => @order
else else
render :action => 'edit' render :action => 'edit'
@ -97,7 +97,7 @@ class OrdersController < ApplicationController
def finish def finish
order = Order.find(params[:id]) order = Order.find(params[:id])
order.finish!(@current_user) order.finish!(@current_user)
redirect_to order, notice: "Die Bestellung wurde beendet." redirect_to order, notice: I18n.t('orders.finish.notice')
end end
# Renders the fax-text-file # Renders the fax-text-file
@ -106,14 +106,14 @@ class OrdersController < ApplicationController
order = Order.find(params[:id]) order = Order.find(params[:id])
supplier = order.supplier supplier = order.supplier
contact = FoodsoftConfig[:contact].symbolize_keys contact = FoodsoftConfig[:contact].symbolize_keys
text = "Bestellung für" + " #{FoodsoftConfig[:name]}" text = I18n.t('orders.fax.heading', :name => FoodsoftConfig[:name])
text += "\n" + "Kundennummer" + ": #{supplier.customer_number}" unless supplier.customer_number.blank? text += "\n" + I18n.t('orders.fax.customer_number') + ': #{supplier.customer_number}' unless supplier.customer_number.blank?
text += "\n" + "Liefertag" + ": " text += "\n" + I18n.t('orders.fax.delivery_day')
text += "\n\n#{supplier.name}\n#{supplier.address}\nFAX: #{supplier.fax}\n\n" text += "\n\n#{supplier.name}\n#{supplier.address}\n" + I18n.t('simple_form.labels.supplier.fax') + ": #{supplier.fax}\n\n"
text += "****** " + "Versandadresse" + "\n\n" text += "****** " + I18n.t('orders.fax.to_address') + "\n\n"
text += "#{FoodsoftConfig[:name]}\n#{contact[:street]}\n#{contact[:zip_code]} #{contact[:city]}\n\n" text += "#{FoodsoftConfig[:name]}\n#{contact[:street]}\n#{contact[:zip_code]} #{contact[:city]}\n\n"
text += "****** " + "Artikel" + "\n\n" text += "****** " + I18n.t('orders.fax.articles') + "\n\n"
text += "Nummer" + " " + "Menge" + " " + "Name" + "\n" text += I18n.t('orders.fax.number') + " " + I18n.t('orders.fax.amount') + " " + I18n.t('orders.fax.name') + "\n"
# now display all ordered articles # now display all ordered articles
order.order_articles.ordered.all(:include => [:article, :article_price]).each do |oa| order.order_articles.ordered.all(:include => [:article, :article_price]).each do |oa|
number = oa.article.order_number number = oa.article.order_number

View file

@ -17,7 +17,7 @@ class PagesController < ApplicationController
elsif params[:id] elsif params[:id]
page = Page.find_by_id(params[:id]) page = Page.find_by_id(params[:id])
if page.nil? if page.nil?
flash[:error] = "Seite existiert nicht!" flash[:error] = I18n.t('pages.cshow.error_noexist')
redirect_to all_pages_path and return redirect_to all_pages_path and return
else else
redirect_to wiki_page_path(page.permalink) and return redirect_to wiki_page_path(page.permalink) and return
@ -29,7 +29,7 @@ class PagesController < ApplicationController
elsif @page.redirect? elsif @page.redirect?
page = Page.find_by_id(@page.redirect) page = Page.find_by_id(@page.redirect)
unless page.nil? unless page.nil?
flash[:notice] = "Weitergeleitet von #{@page.title} ..." flash[:notice] = I18n.t('pages.cshow.redirect_notice', :page => @page.title)
redirect_to wiki_page_path(page.permalink) redirect_to wiki_page_path(page.permalink)
end end
end end
@ -57,7 +57,7 @@ class PagesController < ApplicationController
render :action => 'new' render :action => 'new'
else else
if @page.save if @page.save
flash[:notice] = 'Seite wurde angelegt.' flash[:notice] = I18n.t('pages.create.notice')
redirect_to(wiki_page_path(@page.permalink)) redirect_to(wiki_page_path(@page.permalink))
else else
render :action => "new" render :action => "new"
@ -76,7 +76,7 @@ class PagesController < ApplicationController
if @page.save if @page.save
@page.parent_id = parent_id if (!params[:parent_id].blank? \ @page.parent_id = parent_id if (!params[:parent_id].blank? \
and params[:parent_id] != @page_id) and params[:parent_id] != @page_id)
flash[:notice] = 'Seite wurde aktualisiert.' flash[:notice] = I18n.t('pages.update.notice')
redirect_to wiki_page_path(@page.permalink) redirect_to wiki_page_path(@page.permalink)
else else
render :action => "edit" render :action => "edit"
@ -84,7 +84,7 @@ class PagesController < ApplicationController
end end
rescue ActiveRecord::StaleObjectError rescue ActiveRecord::StaleObjectError
flash[:error] = "Achtung, die Seite wurde gerade von jemand anderes bearbeitet. Bitte versuche es erneut." flash[:error] = I18n.t('pages.error_stale_object')
redirect_to wiki_page_path(@page.permalink) redirect_to wiki_page_path(@page.permalink)
end end
@ -92,7 +92,7 @@ class PagesController < ApplicationController
@page = Page.find(params[:id]) @page = Page.find(params[:id])
@page.destroy @page.destroy
flash[:notice] = "Die Seite '#{@page.title}' und alle Unterseiten wurden erfolgreich gelöscht." flash[:notice] = I18n.t('pages.destroy.notice', :page => @page.title)
redirect_to wiki_path redirect_to wiki_path
end end

View file

@ -17,15 +17,15 @@ class SessionsController < ApplicationController
else else
redirect_to_url = root_url redirect_to_url = root_url
end end
redirect_to redirect_to_url, :notice => "Logged in!" redirect_to redirect_to_url, :notice => I18n.t('sessions.logged_in')
else else
flash.now.alert = "Invalid email or password" flash.now.alert = I18n.t('sessions.login_invalid')
render "new" render "new"
end end
end end
def destroy def destroy
session[:user_id] = nil session[:user_id] = nil
redirect_to login_url, :notice => "Logged out!" redirect_to login_url, :notice => I18n.t('sessions.logged_out')
end end
end end

View file

@ -7,15 +7,15 @@ class StockTakingsController < ApplicationController
def new def new
@stock_taking = StockTaking.new @stock_taking = StockTaking.new
StockArticle.all.each { |a| @stock_taking.stock_changes.build(:stock_article => a) } StockArticle.undeleted.each { |a| @stock_taking.stock_changes.build(:stock_article => a) }
end end
def create def create
create!(:notice => "Inventur wurde erfolgreich angelegt.") create!(:notice => I18n.t('stock_takings.create.notice'))
end end
def update def update
update!(:notice => "Inventur wurde aktualisiert.") update!(:notice => I18n.t('stock_takings.update.notice'))
end end
def fill_new_stock_article_form def fill_new_stock_article_form

View file

@ -1,7 +1,7 @@
class StockitController < ApplicationController class StockitController < ApplicationController
def index def index
@stock_articles = StockArticle.includes(:supplier, :article_category). @stock_articles = StockArticle.undeleted.includes(:supplier, :article_category).
order('suppliers.name, article_categories.name, articles.name') order('suppliers.name, article_categories.name, articles.name')
end end
@ -12,7 +12,7 @@ class StockitController < ApplicationController
def create def create
@stock_article = StockArticle.new(params[:stock_article]) @stock_article = StockArticle.new(params[:stock_article])
if @stock_article.save if @stock_article.save
redirect_to stock_articles_path, :notice => "Lagerartikel wurde gespeichert." redirect_to stock_articles_path, :notice => I18n.t('stockit.stock_create.notice')
else else
render :action => 'new' render :action => 'new'
end end
@ -25,7 +25,7 @@ class StockitController < ApplicationController
def update def update
@stock_article = StockArticle.find(params[:id]) @stock_article = StockArticle.find(params[:id])
if @stock_article.update_attributes(params[:stock_article]) if @stock_article.update_attributes(params[:stock_article])
redirect_to stock_articles_path, :notice => "Lagerartikel wurde gespeichert." redirect_to stock_articles_path, :notice => I18n.t('stockit.stock_update.notice')
else else
render :action => 'edit' render :action => 'edit'
end end
@ -33,11 +33,11 @@ class StockitController < ApplicationController
def destroy def destroy
@article = StockArticle.find(params[:id]) @article = StockArticle.find(params[:id])
@article.destroy @article.mark_as_deleted
render :layout => false render :layout => false
rescue => error rescue => error
render :partial => "destroy_fail", :layout => false, render :partial => "destroy_fail", :layout => false,
:locals => { :fail_msg => "Ein Fehler ist aufgetreten: " + error.message } :locals => { :fail_msg => I18n.t('errors.general_msg', :msg => error.message) }
end end
#TODO: Fix this!! #TODO: Fix this!!

View file

@ -4,7 +4,7 @@ class SuppliersController < ApplicationController
helper :deliveries helper :deliveries
def index def index
@suppliers = Supplier.order(:name) @suppliers = Supplier.undeleted.order(:name)
@deliveries = Delivery.recent @deliveries = Delivery.recent
end end
@ -18,7 +18,7 @@ class SuppliersController < ApplicationController
def new def new
if params[:shared_supplier_id] if params[:shared_supplier_id]
shared_supplier = SharedSupplier.find(params[:shared_supplier_id]) shared_supplier = SharedSupplier.find(params[:shared_supplier_id])
@supplier = shared_supplier.build_supplier(shared_supplier.attributes) @supplier = shared_supplier.build_supplier(shared_supplier.autofill_attributes)
else else
@supplier = Supplier.new @supplier = Supplier.new
end end
@ -27,7 +27,7 @@ class SuppliersController < ApplicationController
def create def create
@supplier = Supplier.new(params[:supplier]) @supplier = Supplier.new(params[:supplier])
if @supplier.save if @supplier.save
flash[:notice] = "Lieferant wurde erstellt" flash[:notice] = I18n.t('suppliers.create.notice')
redirect_to suppliers_path redirect_to suppliers_path
else else
render :action => 'new' render :action => 'new'
@ -41,7 +41,7 @@ class SuppliersController < ApplicationController
def update def update
@supplier = Supplier.find(params[:id]) @supplier = Supplier.find(params[:id])
if @supplier.update_attributes(params[:supplier]) if @supplier.update_attributes(params[:supplier])
flash[:notice] = 'Lieferant wurde aktualisiert' flash[:notice] = I18n.t('suppliers.update.notice')
redirect_to @supplier redirect_to @supplier
else else
render :action => 'edit' render :action => 'edit'
@ -50,11 +50,11 @@ class SuppliersController < ApplicationController
def destroy def destroy
@supplier = Supplier.find(params[:id]) @supplier = Supplier.find(params[:id])
@supplier.destroy @supplier.mark_as_deleted
flash[:notice] = "Lieferant wurde gelöscht" flash[:notice] = I18n.t('suppliers.destroy.notice')
redirect_to suppliers_path redirect_to suppliers_path
rescue => e rescue => e
flash[:error] = "Ein Fehler ist aufgetreten: " + e.message flash[:error] = I18n.t('errors.general_msg', :msg => e.message)
redirect_to @supplier redirect_to @supplier
end end

View file

@ -19,7 +19,7 @@ class TasksController < ApplicationController
def create def create
@task = Task.new(params[:task]) @task = Task.new(params[:task])
if @task.save if @task.save
redirect_to tasks_url, :notice => "Aufgabe wurde erstellt" redirect_to tasks_url, :notice => I18n.t('tasks.create.notice')
else else
render :template => "tasks/new" render :template => "tasks/new"
end end
@ -38,7 +38,7 @@ class TasksController < ApplicationController
@task = Task.find(params[:id]) @task = Task.find(params[:id])
@task.attributes=(params[:task]) @task.attributes=(params[:task])
if @task.errors.empty? && @task.save if @task.errors.empty? && @task.save
flash[:notice] = "Aufgabe wurde aktualisiert" flash[:notice] = I18n.t('tasks.update.notice')
if @task.workgroup if @task.workgroup
redirect_to workgroup_tasks_url(workgroup_id: @task.workgroup_id) redirect_to workgroup_tasks_url(workgroup_id: @task.workgroup_id)
else else
@ -56,7 +56,7 @@ class TasksController < ApplicationController
task.destroy task.destroy
task.update_ordergroup_stats(user_ids) task.update_ordergroup_stats(user_ids)
redirect_to tasks_url, :notice => "Aufgabe wurde gelöscht" redirect_to tasks_url, :notice => I18n.t('tasks.destroy.notice')
end end
# assign current_user to the task and set the assignment to "accepted" # assign current_user to the task and set the assignment to "accepted"
@ -68,7 +68,7 @@ class TasksController < ApplicationController
else else
task.assignments.create(:user => current_user, :accepted => true) task.assignments.create(:user => current_user, :accepted => true)
end end
redirect_to user_tasks_path, :notice => "Du hast die Aufgabe übernommen" redirect_to user_tasks_path, :notice => I18n.t('tasks.accept.notice')
end end
# deletes assignment between current_user and given task # deletes assignment between current_user and given task
@ -79,7 +79,7 @@ class TasksController < ApplicationController
def set_done def set_done
Task.find(params[:id]).update_attribute :done, true Task.find(params[:id]).update_attribute :done, true
redirect_to tasks_url, :notice => "Aufgabenstatus wurde aktualisiert" redirect_to tasks_url, :notice => I18n.t('tasks.set_done.notice')
end end
# Shows all tasks, which are already done # Shows all tasks, which are already done
@ -91,7 +91,7 @@ class TasksController < ApplicationController
def workgroup def workgroup
@group = Group.find(params[:workgroup_id]) @group = Group.find(params[:workgroup_id])
if @group.is_a? Ordergroup if @group.is_a? Ordergroup
redirect_to tasks_url, :alert => "Keine Arbeitsgruppe gefunden" redirect_to tasks_url, :alert => I18n.t('tasks.error_not_found')
end end
end end
end end

View file

@ -2,11 +2,12 @@
class OrderByArticles < OrderPdf class OrderByArticles < OrderPdf
def filename def filename
"Bestellung #{@order.name}-#{@order.ends.to_date} - Artikelsortierung.pdf" I18n.t('documents.order_by_articles.filename', :name => @order.name, :date => @order.ends.to_date) + '.pdf'
end end
def title def title
"Artikelsortierung der Bestellung: #{@order.name}, beendet am #{@order.ends.strftime('%d.%m.%Y')}" I18n.t('documents.order_by_articles.title', :name => @order.name,
:date => @order.ends.strftime(I18n.t('date.formats.default')))
end end
def body def body
@ -14,7 +15,7 @@ class OrderByArticles < OrderPdf
text "#{order_article.article.name} (#{order_article.article.unit} | #{order_article.price.unit_quantity.to_s} | #{number_with_precision(order_article.price.fc_price, precision: 2)})", text "#{order_article.article.name} (#{order_article.article.unit} | #{order_article.price.unit_quantity.to_s} | #{number_with_precision(order_article.price.fc_price, precision: 2)})",
style: :bold, size: 10 style: :bold, size: 10
rows = [] rows = []
rows << %w(Bestellgruppe Menge Preis) rows << I18n.t('documents.order_by_articles.rows')
for goa in order_article.group_order_articles for goa in order_article.group_order_articles
rows << [goa.group_order.ordergroup.name, rows << [goa.group_order.ordergroup.name,
goa.result, goa.result,

View file

@ -2,11 +2,12 @@
class OrderByGroups < OrderPdf class OrderByGroups < OrderPdf
def filename def filename
"Bestellung #{@order.name}-#{@order.ends.to_date} - Gruppensortierung.pdf" I18n.t('documents.order_by_groups.filename', :name => @order.name, :date => @order.ends.to_date) + '.pdf'
end end
def title def title
"Gruppensortierung der Bestellung: #{@order.name}, beendet am #{@order.ends.strftime('%d.%m.%Y')}" I18n.t('documents.order_by_groups.title', :name => @order.name,
:date => @order.ends.strftime(I18n.t('date.formats.default')))
end end
def body def body
@ -16,7 +17,7 @@ class OrderByGroups < OrderPdf
total = 0 total = 0
rows = [] rows = []
rows << %w(Artikel Menge Preis GebGr Einheit Summe) # Table Header rows << I18n.t('documents.order_by_groups.rows') # Table Header
group_order_articles = group_order.group_order_articles.ordered group_order_articles = group_order.group_order_articles.ordered
group_order_articles.each do |goa| group_order_articles.each do |goa|
@ -30,7 +31,7 @@ class OrderByGroups < OrderPdf
goa.order_article.article.unit, goa.order_article.article.unit,
number_with_precision(sub_total, precision: 2)] number_with_precision(sub_total, precision: 2)]
end end
rows << [ "Summe", nil, nil, nil, nil, number_with_precision(total, precision: 2)] rows << [ I18n.t('documents.order_by_groups.sum'), nil, nil, nil, nil, number_with_precision(total, precision: 2)]
table rows, column_widths: [250,50,50,50,50,50], cell_style: {size: 8, overflow: :shrink_to_fit} do |table| table rows, column_widths: [250,50,50,50,50,50], cell_style: {size: 8, overflow: :shrink_to_fit} do |table|
# borders # borders

View file

@ -2,7 +2,7 @@
class OrderFax < OrderPdf class OrderFax < OrderPdf
def filename def filename
"Bestellung #{@order.name}-#{@order.ends.to_date} - Fax.pdf" I18n.t('documents.order_fax.filename', :name => @order.name, :date => @order.ends.to_date) + '.pdf'
end end
def title def title
@ -14,42 +14,40 @@ class OrderFax < OrderPdf
# From paragraph # From paragraph
bounding_box [margin_box.right-200,margin_box.top], width: 200 do bounding_box [margin_box.right-200,margin_box.top], width: 200 do
text FoodsoftConfig[:name], align: :right text FoodsoftConfig[:name], size: 9, align: :right
move_down 5 move_down 5
text contact[:street], align: :right text contact[:street], size: 9, align: :right
move_down 5 move_down 5
text "#{contact[:zip_code]} #{contact[:city]}", align: :right text "#{contact[:zip_code]} #{contact[:city]}", size: 9, align: :right
move_down 5 move_down 5
if @order.supplier.customer_number != '' text "#{I18n.t('simple_form.labels.supplier.customer_number')}: #{@order.supplier.try(:customer_number)}", size: 9, align: :right
text "Kundennummer: #{@order.supplier.customer_number}", align: :right
end
move_down 10
text contact[:phone], size: 9, align: :right
move_down 5 move_down 5
text contact[:email], size: 9, align: :right text "#{I18n.t('simple_form.labels.supplier.phone')}: #{contact[:phone]}", size: 9, align: :right
move_down 5
text "#{I18n.t('simple_form.labels.supplier.email')}: #{contact[:email]}", size: 9, align: :right
end end
# Recipient # Recipient
bounding_box [margin_box.left,margin_box.top-60], width: 200 do bounding_box [margin_box.left,margin_box.top-60], width: 200 do
text @order.name text @order.name
move_down 5 move_down 5
text @order.supplier.address text @order.supplier.try(:address).to_s
move_down 5 move_down 5
text "Fax: " + @order.supplier.fax text "#{I18n.t('simple_form.labels.supplier.fax')}: #{@order.supplier.try(:fax)}"
end end
move_down 5 move_down 5
text Date.today.strftime('%d.%m.%Y'), align: :right text Date.today.strftime(I18n.t('date.formats.default')), align: :right
move_down 10 move_down 10
text "Lieferdatum:" text "#{I18n.t('simple_form.labels.delivery.delivered_on')}:"
move_down 10 move_down 10
text "Ansprechpartner: " + @order.supplier.contact_person text "#{I18n.t('simple_form.labels.supplier.contact_person')}: #{@order.supplier.try(:contact_person)}"
move_down 10 move_down 10
# Articles # Articles
data = [["BestellNr.", "Menge","Name", "Gebinde", "Einheit","Preis/Einheit"]] data = [I18n.t('documents.order_fax.rows')]
data = @order.order_articles.ordered.all(include: :article).collect do |a| data += @order.order_articles.ordered.all(include: :article).collect do |a|
[a.article.order_number, [a.article.order_number,
a.units_to_order, a.units_to_order,
a.article.name, a.article.name,

View file

@ -4,22 +4,23 @@ class OrderMatrix < OrderPdf
MAX_ARTICLES_PER_PAGE = 16 # How many order_articles shoud written on a page MAX_ARTICLES_PER_PAGE = 16 # How many order_articles shoud written on a page
def filename def filename
"Bestellung #{@order.name}-#{@order.ends.to_date} - Sortiermatrix.pdf" I18n.t('documents.order_matrix.filename', :name => @order.name, :date => @order.ends.to_date) + '.pdf'
end end
def title def title
"Sortiermatrix der Bestellung: #{@order.name}, beendet am #{@order.ends.strftime('%d.%m.%Y')}" I18n.t('documents.order_matrix.title', :name => @order.name,
:date => @order.ends.strftime(I18n.t('date.formats.default')))
end end
def body def body
order_articles = @order.order_articles.ordered order_articles = @order.order_articles.ordered
text "Artikelübersicht", style: :bold text I18n.t('documents.order_matrix.heading'), style: :bold
move_down 5 move_down 5
text "Insgesamt #{order_articles.size} Artikel", size: 8 text I18n.t('documents.order_matrix.total', :count => order_articles.size), size: 8
move_down 10 move_down 10
order_articles_data = [%w(Artikel Einheit Gebinde FC-Preis Menge)] order_articles_data = [I18n.t('documents.order_matrix.rows')]
order_articles.each do |a| order_articles.each do |a|
order_articles_data << [a.article.name, order_articles_data << [a.article.name,

View file

@ -58,7 +58,7 @@ module ApplicationHelper
nil nil
end end
html_options = { html_options = {
:title => "Nach #{text} sortieren", :title => I18n.t('helpers.application.sort_by', text: text),
:remote => remote, :remote => remote,
:class => class_name :class => class_name
} }
@ -83,7 +83,7 @@ module ApplicationHelper
# Returns the weekday. 0 is sunday, 1 is monday and so on # Returns the weekday. 0 is sunday, 1 is monday and so on
def weekday(dayNumber) def weekday(dayNumber)
weekdays = ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"] weekdays = I18n.t('date.day_names')
return weekdays[dayNumber] return weekdays[dayNumber]
end end
@ -103,9 +103,9 @@ module ApplicationHelper
def icon(name, options={}) def icon(name, options={})
icons = { icons = {
:delete => { :file => 'b_drop.png', :alt => 'Löschen'}, :delete => { :file => 'b_drop.png', :alt => I18n.t('ui.delete')},
:edit => { :file => 'b_edit.png', :alt => 'Bearbeiten'}, :edit => { :file => 'b_edit.png', :alt => I18n.t('ui.edit')},
:members => { :file => 'b_users.png', :alt => 'Mitlglieder bearbeiten'} :members => { :file => 'b_users.png', :alt => I18n.t('helpers.application.edit_user')}
} }
options[:alt] ||= icons[name][:alt] options[:alt] ||= icons[name][:alt]
options[:title] ||= icons[name][:title] options[:title] ||= icons[name][:title]
@ -126,16 +126,16 @@ module ApplicationHelper
def format_roles(record) def format_roles(record)
roles = [] roles = []
roles << 'Admin' if record.role_admin? roles << I18n.t('helpers.application.role_admin') if record.role_admin?
roles << 'Finanzen' if record.role_finance? roles << I18n.t('helpers.application.role_finance') if record.role_finance?
roles << 'Lieferanten' if record.role_suppliers? roles << I18n.t('helpers.application.role_suppliers') if record.role_suppliers?
roles << 'Artikel' if record.role_article_meta? roles << I18n.t('helpers.application.role_article_meta') if record.role_article_meta?
roles << 'Bestellung' if record.role_orders? roles << I18n.t('helpers.application.role_orders') if record.role_orders?
roles.join(', ') roles.join(', ')
end end
def link_to_gmaps(address) def link_to_gmaps(address)
link_to h(address), "http://maps.google.de/?q=#{h(address)}", :title => "Show it on google maps", link_to h(address), "http://maps.google.com/?q=#{h(address)}", :title => I18n.t('helpers.application.show_google_maps'),
:target => "_blank" :target => "_blank"
end end
@ -143,7 +143,7 @@ module ApplicationHelper
# checks for nil (useful for relations) # checks for nil (useful for relations)
def link_to_user_message_if_valid(user) def link_to_user_message_if_valid(user)
user.nil? ? '??' : link_to(user.nick, new_message_path('message[mail_to]' => user.id), user.nil? ? '??' : link_to(user.nick, new_message_path('message[mail_to]' => user.id),
:title => 'Nachricht schreiben') :title => I18n.t('helpers.application.write_message'))
end end
def bootstrap_flash def bootstrap_flash
@ -152,7 +152,7 @@ module ApplicationHelper
type = :success if type == :notice type = :success if type == :notice
type = :error if type == :alert type = :error if type == :alert
text = content_tag(:div, text = content_tag(:div,
content_tag(:button, raw("&times;"), :class => "close", "data-dismiss" => "alert") + content_tag(:button, I18n.t('ui.marks.close').html_safe, :class => "close", "data-dismiss" => "alert") +
message, :class => "alert fade in alert-#{type}") message, :class => "alert fade in alert-#{type}")
flash_messages << text if message flash_messages << text if message
end end

View file

@ -3,15 +3,15 @@ module DeliveriesHelper
def link_to_invoice(delivery) def link_to_invoice(delivery)
if delivery.invoice if delivery.invoice
link_to number_to_currency(delivery.invoice.amount), [:finance, delivery.invoice], link_to number_to_currency(delivery.invoice.amount), [:finance, delivery.invoice],
title: "Rechnung anzeigen" title: I18n.t('helpers.deliveries.show_invoice')
else else
link_to "Rechnung anlegen", new_finance_invoice_path(supplier_id: delivery.supplier.id, delivery_id: delivery.id), link_to I18n.t('helpers.deliveries.new_invoice'), new_finance_invoice_path(supplier_id: delivery.supplier.id, delivery_id: delivery.id),
class: 'btn btn-mini' class: 'btn btn-mini'
end end
end end
def stock_articles_for_select(supplier) def stock_articles_for_select(supplier)
supplier.stock_articles.map {|a| ["#{a.name} (#{number_to_currency a.price}/#{a.unit})", a.id] } supplier.stock_articles.undeleted.reorder('articles.name ASC').map {|a| ["#{a.name} (#{number_to_currency a.price}/#{a.unit})", a.id] }
end end
end end

View file

@ -15,6 +15,6 @@ module MessagesHelper
link_text = content_tag :id, nil, class: 'icon-envelope' link_text = content_tag :id, nil, class: 'icon-envelope'
link_text << " #{options[:text]}" if options[:text].present? link_text << " #{options[:text]}" if options[:text].present?
link_to(link_text.html_safe, new_message_path(message: messages_params), class: 'btn', link_to(link_text.html_safe, new_message_path(message: messages_params), class: 'btn',
title: 'Nachricht verschicken') title: I18n.t('helpers.submit.message.create'))
end end
end end

View file

@ -6,13 +6,13 @@ module OrdersHelper
end end
def order_pdf(order, document, text) def order_pdf(order, document, text)
link_to text, order_path(order, document: document, format: :pdf), title: "PDF erstellen" link_to text, order_path(order, document: document, format: :pdf), title: I18n.t('helpers.orders.order_pdf')
end end
def options_for_suppliers_to_select def options_for_suppliers_to_select
options = [["Lieferantin/Lager auswählen"]] options = [[I18n.t('helpers.orders.option_choose')]]
options += Supplier.all.map {|s| [ s.name, url_for(action: "new", supplier_id: s)] } options += Supplier.all.map {|s| [ s.name, url_for(action: "new", supplier_id: s)] }
options += [["Lager", url_for(action: 'new', supplier_id: 0)]] options += [[I18n.t('helpers.orders.option_stock'), url_for(action: 'new', supplier_id: 0)]]
options_for_select(options) options_for_select(options)
end end
end end

View file

@ -10,7 +10,7 @@ module TasksHelper
def highlighted_required_users(task) def highlighted_required_users(task)
unless task.enough_users_assigned? unless task.enough_users_assigned?
content_tag :span, task.still_required_users, class: 'badge badge-important', content_tag :span, task.still_required_users, class: 'badge badge-important',
title: "Es fehlen #{task.still_required_users} Mitstreiterinnen!" title: I18n.t('helpers.tasks.required_users', :count => task.still_required_users)
end end
end end
end end

View file

@ -26,7 +26,7 @@ class Mailer < ActionMailer::Base
@link = new_password_url(id: @user.id, token: @user.reset_password_token) @link = new_password_url(id: @user.id, token: @user.reset_password_token)
mail :to => @user.email, mail :to => @user.email,
:subject => "[#{FoodsoftConfig[:name]}] Neues Passwort für/ New password for #{@user.nick}" :subject => "[#{FoodsoftConfig[:name]}] " + I18n.t('mailer.reset_password.subject', :username => @user.nick)
end end
# Sends an invite email. # Sends an invite email.
@ -36,7 +36,7 @@ class Mailer < ActionMailer::Base
@link = accept_invitation_url(token: @invite.token) @link = accept_invitation_url(token: @invite.token)
mail :to => @invite.email, mail :to => @invite.email,
:subject => "Einladung in die Foodcoop #{FoodsoftConfig[:name]} - Invitation to the Foodcoop" :subject => I18n.t('mailer.invite.subject')
end end
# Notify user of upcoming task. # Notify user of upcoming task.
@ -46,7 +46,7 @@ class Mailer < ActionMailer::Base
@task = task @task = task
mail :to => user.email, mail :to => user.email,
:subject => "[#{FoodsoftConfig[:name]}] Aufgaben werden fällig!" :subject => "[#{FoodsoftConfig[:name]}] " + I18n.t('mailer.upcoming_tasks.subject')
end end
# Sends order result for specific Ordergroup # Sends order result for specific Ordergroup
@ -56,7 +56,7 @@ class Mailer < ActionMailer::Base
@group_order = group_order @group_order = group_order
mail :to => user.email, mail :to => user.email,
:subject => "[#{FoodsoftConfig[:name]}] Bestellung beendet: #{group_order.order.name}" :subject => "[#{FoodsoftConfig[:name]}] " + I18n.t('mailer.order_result.subject', :name => group_order.order.name)
end end
# Notify user if account balance is less than zero # Notify user if account balance is less than zero
@ -66,7 +66,7 @@ class Mailer < ActionMailer::Base
@transaction = transaction @transaction = transaction
mail :to => user.email, mail :to => user.email,
:subject => "[#{FoodsoftConfig[:name]}] Gruppenkonto im Minus" :subject => "[#{FoodsoftConfig[:name]}] " + I18n.t('mailer.negative_balance')
end end
def feedback(user, feedback) def feedback(user, feedback)
@ -78,7 +78,7 @@ class Mailer < ActionMailer::Base
:from => "#{user.nick} <#{user.email}>", :from => "#{user.nick} <#{user.email}>",
:sender => FoodsoftConfig[:notification]["sender_address"], :sender => FoodsoftConfig[:notification]["sender_address"],
:errors_to => FoodsoftConfig[:notification]["sender_address"], :errors_to => FoodsoftConfig[:notification]["sender_address"],
:subject => "[Foodsoft] Feeback von #{user.email}" :subject => "[#{FoodsoftConfig[:name]}] " + I18n.t('mailer.feedback.subject', :email => user.email)
end end
def not_enough_users_assigned(task, user) def not_enough_users_assigned(task, user)
@ -87,7 +87,7 @@ class Mailer < ActionMailer::Base
@user = user @user = user
mail :to => user.email, mail :to => user.email,
:subject => "[#{FoodsoftConfig[:name]}] \"#{task.name}\" braucht noch Leute!" :subject => "[#{FoodsoftConfig[:name]}] " + I18n.t('mailer.not_enough_users_assigned.subject', :task => task.name)
end end
private private

View file

@ -1,24 +1,25 @@
# encoding: utf-8 # encoding: utf-8
class Article < ActiveRecord::Base class Article < ActiveRecord::Base
acts_as_paranoid # Avoid deleting the article for consistency of order-results
extend ActiveSupport::Memoizable # Ability to cache method results. Use memoize :expensive_method extend ActiveSupport::Memoizable # Ability to cache method results. Use memoize :expensive_method
# Replace numeric seperator with database format # Replace numeric seperator with database format
localize_input_of :price, :tax, :deposit localize_input_of :price, :tax, :deposit
# Associations # Associations
belongs_to :supplier, :with_deleted => true belongs_to :supplier
belongs_to :article_category belongs_to :article_category
has_many :article_prices, :order => "created_at DESC" has_many :article_prices, :order => "created_at DESC"
scope :available, :conditions => {:availability => true} scope :undeleted, -> { where(deleted_at: nil) }
scope :available, -> { undeleted.where(availability: true) }
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 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, :greater_than_or_equal_to => 0
validates_numericality_of :unit_quantity, :greater_than => 0
validates_numericality_of :deposit, :tax validates_numericality_of :deposit, :tax
validates_uniqueness_of :name, :scope => [:supplier_id, :deleted_at, :type] validates_uniqueness_of :name, :scope => [:supplier_id, :deleted_at, :type]
@ -49,6 +50,11 @@ class Article < ActiveRecord::Base
end end
memoize :in_open_order memoize :in_open_order
# Returns true if the article has been ordered in the given order at least once
def ordered_in_order?(order)
order.order_articles.where(article_id: id).where('quantity > 0').one?
end
# this method checks, if the shared_article has been changed # this method checks, if the shared_article has been changed
# unequal attributes will returned in array # unequal attributes will returned in array
# if only the timestamps differ and the attributes are equal, # if only the timestamps differ and the attributes are equal,
@ -136,11 +142,20 @@ class Article < ActiveRecord::Base
end end
end end
def deleted?
deleted_at.present?
end
def mark_as_deleted
check_article_in_use
update_column :deleted_at, Time.now
end
protected protected
# Checks if the article is in use before it will deleted # Checks if the article is in use before it will deleted
def check_article_in_use def check_article_in_use
raise self.name.to_s + " kann nicht gelöscht werden. Der Artikel befindet sich in einer laufenden Bestellung!" if self.in_open_order raise I18n.t('articles.model.error_in_use', :article => self.name.to_s) if self.in_open_order
end end
# Create an ArticlePrice, when the price-attr are changed. # Create an ArticlePrice, when the price-attr are changed.

View file

@ -8,7 +8,7 @@ class ArticleCategory < ActiveRecord::Base
protected protected
def check_for_associated_articles def check_for_associated_articles
raise I18n.t('activerecord.errors.has_many_left', collection: Article.model_name.human) if articles.exists? raise I18n.t('activerecord.errors.has_many_left', collection: Article.model_name.human) if articles.undeleted.exists?
end end
end end

View file

@ -1,10 +1,11 @@
class ArticlePrice < ActiveRecord::Base class ArticlePrice < ActiveRecord::Base
belongs_to :article, :with_deleted => true belongs_to :article
has_many :order_articles has_many :order_articles
validates_presence_of :price, :tax, :deposit, :unit_quantity validates_presence_of :price, :tax, :deposit, :unit_quantity
validates_numericality_of :price, :unit_quantity, :greater_than => 0 validates_numericality_of :price, :greater_than_or_equal_to => 0
validates_numericality_of :unit_quantity, :greater_than => 0
validates_numericality_of :deposit, :tax validates_numericality_of :deposit, :tax
localize_input_of :price, :tax, :deposit localize_input_of :price, :tax, :deposit

View file

@ -1,6 +1,6 @@
class Delivery < ActiveRecord::Base class Delivery < ActiveRecord::Base
belongs_to :supplier, :with_deleted => true belongs_to :supplier
has_one :invoice has_one :invoice
has_many :stock_changes, :dependent => :destroy has_many :stock_changes, :dependent => :destroy

View file

@ -1,7 +1,7 @@
# financial transactions are the foodcoop internal financial transactions # financial transactions are the foodcoop internal financial transactions
# only ordergroups have an account balance and are happy to transfer money # only ordergroups have an account balance and are happy to transfer money
class FinancialTransaction < ActiveRecord::Base class FinancialTransaction < ActiveRecord::Base
belongs_to :ordergroup, :with_deleted => true belongs_to :ordergroup
belongs_to :user belongs_to :user
validates_presence_of :amount, :note, :user_id, :ordergroup_id validates_presence_of :amount, :note, :user_id, :ordergroup_id

View file

@ -1,13 +1,15 @@
# Groups organize the User. # Groups organize the User.
# A Member gets the roles from the Group # A Member gets the roles from the Group
class Group < ActiveRecord::Base class Group < ActiveRecord::Base
has_many :memberships, :dependent => :destroy has_many :memberships
has_many :users, :through => :memberships has_many :users, :through => :memberships
validates :name, :presence => true, :length => {:in => 1..25} validates :name, :presence => true, :length => {:in => 1..25}
attr_reader :user_tokens attr_reader :user_tokens
scope :undeleted, -> { where(deleted_at: nil) }
# Returns true if the given user if is an member of this group. # Returns true if the given user if is an member of this group.
def member?(user) def member?(user)
memberships.find_by_user_id(user.id) memberships.find_by_user_id(user.id)
@ -22,6 +24,18 @@ class Group < ActiveRecord::Base
self.user_ids = ids.split(",") self.user_ids = ids.split(",")
end end
def deleted?
deleted_at.present?
end
def mark_as_deleted
# TODO: Checks for participating in not closed orders
transaction do
memberships.destroy_all
# TODO: What should happen to users?
update_column :deleted_at, Time.now
end
end
end end

View file

@ -4,7 +4,7 @@ class GroupOrder < ActiveRecord::Base
attr_accessor :group_order_articles_attributes attr_accessor :group_order_articles_attributes
belongs_to :order belongs_to :order
belongs_to :ordergroup, :with_deleted => true belongs_to :ordergroup
has_many :group_order_articles, :dependent => :destroy has_many :group_order_articles, :dependent => :destroy
has_many :order_articles, :through => :group_order_articles has_many :order_articles, :through => :group_order_articles
belongs_to :updated_by, :class_name => "User", :foreign_key => "updated_by_user_id" belongs_to :updated_by, :class_name => "User", :foreign_key => "updated_by_user_id"

View file

@ -27,7 +27,7 @@ class Invite < ActiveRecord::Base
# Custom validation: check that email does not already belong to a registered user. # Custom validation: check that email does not already belong to a registered user.
def email_not_already_registered def email_not_already_registered
unless User.find_by_email(self.email).nil? unless User.find_by_email(self.email).nil?
errors.add(:email, 'ist bereits in Verwendung. Person ist schon Mitglied der Foodcoop.') errors.add(:email, I18n.t('invites.errors.already_member'))
end end
end end

View file

@ -1,6 +1,6 @@
class Invoice < ActiveRecord::Base class Invoice < ActiveRecord::Base
belongs_to :supplier, :with_deleted => true belongs_to :supplier
belongs_to :delivery belongs_to :delivery
belongs_to :order belongs_to :order

View file

@ -6,7 +6,7 @@ class Membership < ActiveRecord::Base
before_destroy :check_last_admin before_destroy :check_last_admin
# messages # messages
ERR_NO_ADMIN_MEMBER_DELETE = "Mitgliedschaft kann nicht beendet werden. Du bist die letzte Administratorin" ERR_NO_ADMIN_MEMBER_DELETE = I18n.t('model.membership.no_admin_delete')
protected protected

View file

@ -2,7 +2,7 @@ class Message < ActiveRecord::Base
belongs_to :sender, :class_name => "User", :foreign_key => "sender_id" belongs_to :sender, :class_name => "User", :foreign_key => "sender_id"
serialize :recipients_ids, Array serialize :recipients_ids, Array
attr_accessor :sent_to_all, :group_id, :recipient_tokens attr_accessor :sent_to_all, :group_id, :recipient_tokens, :reply_to
scope :pending, where(:email_state => 0) scope :pending, where(:email_state => 0)
scope :sent, where(:email_state => 1) scope :sent, where(:email_state => 1)
@ -46,11 +46,11 @@ class Message < ActiveRecord::Base
end end
def reply_to=(message_id) def reply_to=(message_id)
message = Message.find(message_id) @reply_to = Message.find(message_id)
add_recipients([message.sender]) add_recipients([@reply_to.sender])
self.subject = "Re: #{message.subject}" self.subject = I18n.t('messages.model.reply_subject', :subject => @reply_to.subject)
self.body = "#{message.sender.nick} schrieb am #{I18n.l(message.created_at, :format => :short)}:\n" self.body = I18n.t('messages.model.reply_header', :user => @reply_to.sender.nick, :when => I18n.l(@reply_to.created_at, :format => :short)) + "\n"
message.body.each_line{ |l| self.body += "> #{l}" } @reply_to.body.each_line{ |l| self.body += I18n.t('messages.model.reply_indent', :line => l) }
end end
def mail_to=(user_id) def mail_to=(user_id)
@ -64,7 +64,7 @@ class Message < ActiveRecord::Base
end end
def sender_name def sender_name
system_message? ? 'Foodsoft' : sender.nick rescue "??" system_message? ? I18n.t('layouts.foodsoft') : sender.nick rescue "??"
end end
def recipients def recipients
@ -83,6 +83,10 @@ class Message < ActiveRecord::Base
end end
update_attribute(:email_state, 1) update_attribute(:email_state, 1)
end end
def is_readable_for?(user)
!private || sender == user || recipients_ids.include?(user.id)
end
end end

View file

@ -10,7 +10,7 @@ class Order < ActiveRecord::Base
has_one :invoice has_one :invoice
has_many :comments, :class_name => "OrderComment", :order => "created_at" has_many :comments, :class_name => "OrderComment", :order => "created_at"
has_many :stock_changes has_many :stock_changes
belongs_to :supplier, :with_deleted => true belongs_to :supplier
belongs_to :updated_by, :class_name => 'User', :foreign_key => 'updated_by_user_id' belongs_to :updated_by, :class_name => 'User', :foreign_key => 'updated_by_user_id'
belongs_to :created_by, :class_name => 'User', :foreign_key => 'created_by_user_id' belongs_to :created_by, :class_name => 'User', :foreign_key => 'created_by_user_id'
@ -38,9 +38,11 @@ class Order < ActiveRecord::Base
def articles_for_ordering def articles_for_ordering
if stockit? if stockit?
# make sure to include those articles which are no longer available
# but which have already been ordered in this stock order
StockArticle.available.all(:include => :article_category, StockArticle.available.all(:include => :article_category,
:order => 'article_categories.name, articles.name').reject{ |a| :order => 'article_categories.name, articles.name').reject{ |a|
a.quantity_available <= 0 a.quantity_available <= 0 and not a.ordered_in_order?(self)
}.group_by { |a| a.article_category.name } }.group_by { |a| a.article_category.name }
else else
supplier.articles.available.all.group_by { |a| a.article_category.name } supplier.articles.available.all.group_by { |a| a.article_category.name }
@ -113,7 +115,7 @@ class Order < ActiveRecord::Base
def sum(type = :gross) def sum(type = :gross)
total = 0 total = 0
if type == :net || type == :gross || type == :fc if type == :net || type == :gross || type == :fc
for oa in order_articles.ordered.all(:include => [:article,:article_price]) for oa in order_articles.ordered.includes(:article, :article_price)
quantity = oa.units_to_order * oa.price.unit_quantity quantity = oa.units_to_order * oa.price.unit_quantity
case type case type
when :net when :net
@ -125,8 +127,8 @@ class Order < ActiveRecord::Base
end end
end end
elsif type == :groups || type == :groups_without_markup elsif type == :groups || type == :groups_without_markup
for go in group_orders.all(:include => :group_order_articles) for go in group_orders.includes(group_order_articles: {order_article: [:article, :article_price]})
for goa in go.group_order_articles.all(:include => [:order_article]) for goa in go.group_order_articles
case type case type
when :groups when :groups
total += goa.result * goa.order_article.price.fc_price total += goa.result * goa.order_article.price.fc_price
@ -156,7 +158,7 @@ class Order < ActiveRecord::Base
goa.save_results! goa.save_results!
# Delete no longer required order-history (group_order_article_quantities) and # Delete no longer required order-history (group_order_article_quantities) and
# TODO: Do we need articles, which aren't ordered? (units_to_order == 0 ?) # TODO: Do we need articles, which aren't ordered? (units_to_order == 0 ?)
goa.group_order_article_quantities.clear #goa.group_order_article_quantities.clear
end end
end end
@ -174,8 +176,9 @@ class Order < ActiveRecord::Base
# Sets order.status to 'close' and updates all Ordergroup.account_balances # Sets order.status to 'close' and updates all Ordergroup.account_balances
def close!(user) def close!(user)
raise "Bestellung wurde schon abgerechnet" if closed? raise I18n.t('orders.model.error_closed') if closed?
transaction_note = "Bestellung: #{name}, bis #{ends.strftime('%d.%m.%Y')}" transaction_note = I18n.t('orders.model.notice_close', :name => name,
:ends => ends.strftime(I18n.t('date.formats.default')))
gos = group_orders.all(:include => :ordergroup) # Fetch group_orders gos = group_orders.all(:include => :ordergroup) # Fetch group_orders
gos.each { |group_order| group_order.update_price! } # Update prices of group_orders gos.each { |group_order| group_order.update_price! } # Update prices of group_orders
@ -199,18 +202,18 @@ class Order < ActiveRecord::Base
# Close the order directly, without automaticly updating ordergroups account balances # Close the order directly, without automaticly updating ordergroups account balances
def close_direct!(user) def close_direct!(user)
raise "Bestellung wurde schon abgerechnet" if closed? raise I18n.t('orders.model.error_closed') if closed?
update_attributes! state: 'closed', updated_by: user update_attributes! state: 'closed', updated_by: user
end end
protected protected
def starts_before_ends def starts_before_ends
errors.add(:ends, "muss nach dem Bestellstart liegen (oder leer bleiben)") if (ends && starts && ends <= starts) errors.add(:ends, I18n.t('articles.model.error_starts_before_ends')) if (ends && starts && ends <= starts)
end end
def include_articles def include_articles
errors.add(:articles, "Es muss mindestens ein Artikel ausgewählt sein") if article_ids.empty? errors.add(:articles, I18n.t('articles.model.error_nosel')) if article_ids.empty?
end end
def save_order_articles def save_order_articles

View file

@ -4,7 +4,7 @@ class OrderArticle < ActiveRecord::Base
attr_reader :update_current_price attr_reader :update_current_price
belongs_to :order belongs_to :order
belongs_to :article, :with_deleted => true belongs_to :article
belongs_to :article_price belongs_to :article_price
has_many :group_order_articles, :dependent => :destroy has_many :group_order_articles, :dependent => :destroy
@ -93,7 +93,7 @@ class OrderArticle < ActiveRecord::Base
end end
# Updates order_article and belongings during balancing process # Updates order_article and belongings during balancing process
def update_article_and_price!(article_attributes, price_attributes, order_article_attributes) def update_article_and_price!(order_article_attributes, article_attributes, price_attributes = nil)
OrderArticle.transaction do OrderArticle.transaction do
# Updates self # Updates self
self.update_attributes!(order_article_attributes) self.update_attributes!(order_article_attributes)
@ -102,6 +102,7 @@ class OrderArticle < ActiveRecord::Base
article.update_attributes!(article_attributes) article.update_attributes!(article_attributes)
# Updates article_price belonging to current order article # Updates article_price belonging to current order article
if price_attributes.present?
article_price.attributes = price_attributes article_price.attributes = price_attributes
if article_price.changed? if article_price.changed?
# Updates also price attributes of article if update_current_price is selected # Updates also price attributes of article if update_current_price is selected
@ -119,6 +120,7 @@ class OrderArticle < ActiveRecord::Base
end end
end end
end end
end
def update_current_price=(value) def update_current_price=(value)
@update_current_price = (value == true or value == '1') ? true : false @update_current_price = (value == true or value == '1') ? true : false
@ -134,7 +136,7 @@ class OrderArticle < ActiveRecord::Base
private private
def article_and_price_exist def article_and_price_exist
errors.add(:article, "muss angegeben sein und einen aktuellen Preis haben") if !(article = Article.find(article_id)) || article.fc_price.nil? errors.add(:article, I18n.t('model.order_article.error_price')) if !(article = Article.find(article_id)) || article.fc_price.nil?
end end
# Associate with current article price if created in a finished order # Associate with current article price if created in a finished order
@ -146,7 +148,10 @@ class OrderArticle < ActiveRecord::Base
end end
def update_ordergroup_prices def update_ordergroup_prices
group_order_articles.each { |goa| goa.group_order.update_price! } # updates prices of ALL ordergroups - these are actually too many
# in case of performance issues, update only ordergroups, which ordered this article
# CAUTION: in after_destroy callback related records (e.g. group_order_articles) are already non-existent
order.group_orders.each { |go| go.update_price! }
end end
end end

View file

@ -8,14 +8,13 @@ class Ordergroup < Group
APPLE_MONTH_AGO = 6 # How many month back we will count tasks and orders sum APPLE_MONTH_AGO = 6 # How many month back we will count tasks and orders sum
acts_as_paranoid # Avoid deleting the ordergroup for consistency of order-results
serialize :stats serialize :stats
has_many :financial_transactions has_many :financial_transactions
has_many :group_orders has_many :group_orders
has_many :orders, :through => :group_orders has_many :orders, :through => :group_orders
validates_numericality_of :account_balance, :message => 'ist keine gültige Zahl' validates_numericality_of :account_balance, :message => I18n.t('ordergroups.model.invalid_balance')
validate :uniqueness_of_name, :uniqueness_of_members validate :uniqueness_of_name, :uniqueness_of_members
after_create :update_stats! after_create :update_stats!
@ -103,7 +102,7 @@ class Ordergroup < Group
# Make sure, that a user can only be in one ordergroup # Make sure, that a user can only be in one ordergroup
def uniqueness_of_members def uniqueness_of_members
users.each do |user| users.each do |user|
errors.add :user_tokens, "#{user.nick} ist schon in einer anderen Bestellgruppe" if user.groups.where(:type => 'Ordergroup').size > 1 errors.add :user_tokens, I18n.t('ordergroups.model.error_single_group', :user => user.nick) if user.groups.where(:type => 'Ordergroup').size > 1
end end
end end
@ -117,5 +116,15 @@ class Ordergroup < Group
end end
end end
# Make sure, the name is uniq, add usefull message if uniq group is already deleted
def uniqueness_of_name
id = new_record? ? '' : self.id
group = Ordergroup.where('groups.id != ? AND groups.name = ?', id, name).first
if group.present?
message = group.deleted? ? :taken_with_deleted : :taken
errors.add :name, message
end
end
end end

View file

@ -47,7 +47,7 @@ class Page < ActiveRecord::Base
unless old_title.blank? unless old_title.blank?
Page.create :redirect => id, Page.create :redirect => id,
:title => old_title, :title => old_title,
:body => "Weiterleitung auf [[#{title}]]..", :body => I18n.t('model.page.redirect', :title => title),
:permalink => Page.permalink(old_title), :permalink => Page.permalink(old_title),
:updated_by => updated_by :updated_by => updated_by
end end

View file

@ -8,5 +8,11 @@ class SharedSupplier < ActiveRecord::Base
has_one :supplier has_one :supplier
has_many :shared_articles, :foreign_key => :supplier_id has_many :shared_articles, :foreign_key => :supplier_id
# These set of attributes are used to autofill attributes of new supplier,
# when created by import from shared supplier feature.
def autofill_attributes
whitelist = %w(name address phone fax email url delivery_days note)
attributes.select { |k,_v| whitelist.include?(k) }
end
end end

View file

@ -1,10 +1,9 @@
# encoding: utf-8 # encoding: utf-8
class StockArticle < Article class StockArticle < Article
acts_as_paranoid
has_many :stock_changes has_many :stock_changes
scope :available, :conditions => "quantity > 0" scope :available, -> { undeleted.where'quantity > 0' }
before_destroy :check_quantity before_destroy :check_quantity
@ -23,10 +22,15 @@ class StockArticle < Article
available.collect { |a| a.quantity * a.gross_price }.sum available.collect { |a| a.quantity * a.gross_price }.sum
end end
def mark_as_deleted
check_quantity
super
end
protected protected
def check_quantity def check_quantity
raise "#{name} kann nicht gelöscht werden. Der Lagerbestand ist nicht null." unless quantity == 0 raise I18n.t('stockit.check.not_empty', :name => name) unless quantity == 0
end end
# Overwrite Price history of Article. For StockArticles isn't it necessary. # Overwrite Price history of Article. For StockArticles isn't it necessary.

View file

@ -1,7 +1,7 @@
class StockChange < ActiveRecord::Base class StockChange < ActiveRecord::Base
belongs_to :delivery belongs_to :delivery
belongs_to :order belongs_to :order
belongs_to :stock_article, with_deleted: true belongs_to :stock_article
validates_presence_of :stock_article_id, :quantity validates_presence_of :stock_article_id, :quantity
validates_numericality_of :quantity validates_numericality_of :quantity

View file

@ -1,7 +1,7 @@
# encoding: utf-8
class Supplier < ActiveRecord::Base class Supplier < ActiveRecord::Base
acts_as_paranoid # Avoid deleting the supplier for consistency of order-results
has_many :articles, :dependent => :destroy, :conditions => {:type => nil}, has_many :articles, :conditions => {:type => nil},
:include => [:article_category], :order => 'article_categories.name, articles.name' :include => [:article_category], :order => 'article_categories.name, articles.name'
has_many :stock_articles, :include => [:article_category], :order => 'article_categories.name, articles.name' has_many :stock_articles, :include => [:article_category], :order => 'article_categories.name, articles.name'
has_many :orders has_many :orders
@ -20,13 +20,15 @@ class Supplier < ActiveRecord::Base
validates_length_of :address, :in => 8..50 validates_length_of :address, :in => 8..50
validate :uniqueness_of_name validate :uniqueness_of_name
scope :undeleted, -> { where(deleted_at: nil) }
# sync all articles with the external database # sync all articles with the external database
# returns an array with articles(and prices), which should be updated (to use in a form) # returns an array with articles(and prices), which should be updated (to use in a form)
# also returns an array with outlisted_articles, which should be deleted # also returns an array with outlisted_articles, which should be deleted
def sync_all def sync_all
updated_articles = Array.new updated_articles = Array.new
outlisted_articles = Array.new outlisted_articles = Array.new
for article in articles for article in articles.undeleted
# try to find the associated shared_article # try to find the associated shared_article
shared_article = article.shared_article shared_article = article.shared_article
@ -65,12 +67,23 @@ class Supplier < ActiveRecord::Base
return [updated_articles, outlisted_articles] return [updated_articles, outlisted_articles]
end end
def deleted?
deleted_at.present?
end
def mark_as_deleted
transaction do
update_column :deleted_at, Time.now
articles.each(&:mark_as_deleted)
end
end
protected protected
# Make sure, the name is uniq, add usefull message if uniq group is already deleted # Make sure, the name is uniq, add usefull message if uniq group is already deleted
def uniqueness_of_name def uniqueness_of_name
id = new_record? ? '' : self.id id = new_record? ? '' : self.id
supplier = Supplier.with_deleted.where('suppliers.id != ? AND suppliers.name = ?', id, name).first supplier = Supplier.where('suppliers.id != ? AND suppliers.name = ?', id, name).first
if supplier.present? if supplier.present?
message = supplier.deleted? ? :taken_with_deleted : :taken message = supplier.deleted? ? :taken_with_deleted : :taken
errors.add :name, message errors.add :name, message

View file

@ -75,13 +75,10 @@ class Task < ActiveRecord::Base
# and makes the users responsible for the task # and makes the users responsible for the task
# TODO: check for maximal number of users # TODO: check for maximal number of users
def user_list=(ids) def user_list=(ids)
list = ids.split(",") list = ids.split(",").map(&:to_i)
new_users = (list - users.collect(&:id)).uniq new_users = (list - users.collect(&:id)).uniq
old_users = users.reject { |user| list.include?(user.id) } old_users = users.reject { |user| list.include?(user.id) }
logger.debug "[debug] New users: #{new_users}"
logger.debug "Old users: #{old_users}"
self.class.transaction do self.class.transaction do
# delete old assignments # delete old assignments
if old_users.any? if old_users.any?
@ -93,7 +90,7 @@ class Task < ActiveRecord::Base
if user.blank? if user.blank?
errors.add(:user_list) errors.add(:user_list)
else else
if id == current_user_id if id == current_user_id.to_i
# current_user will accept, when he puts himself to the list of users # current_user will accept, when he puts himself to the list of users
self.assignments.build :user => user, :accepted => true self.assignments.build :user => user, :accepted => true
else else

View file

@ -44,13 +44,13 @@ class User < ActiveRecord::Base
# returns the User-settings and the translated description # returns the User-settings and the translated description
def self.setting_keys def self.setting_keys
{ {
"notify.orderFinished" => 'Informier mich über meine Bestellergebnisse (nach Ende der Bestellung).', "notify.orderFinished" => I18n.t('model.user.notify.order_finished'),
"notify.negativeBalance" => 'Informiere mich, falls meine Bestellgruppe ins Minus rutscht.', "notify.negativeBalance" => I18n.t('model.user.notify.negative_balance'),
"notify.upcoming_tasks" => 'Erinnere mich an anstehende Aufgaben.', "notify.upcoming_tasks" => I18n.t('model.user.notify.upcoming_tasks'),
"messages.sendAsEmail" => 'Bekomme Nachrichten als Emails.', "messages.sendAsEmail" => I18n.t('model.user.notify.send_as_email'),
"profile.phoneIsPublic" => 'Telefon ist für Mitglieder sichtbar', "profile.phoneIsPublic" => I18n.t('model.user.notify.phone_is_public'),
"profile.emailIsPublic" => 'E-Mail ist für Mitglieder sichtbar', "profile.emailIsPublic" => I18n.t('model.user.notify.email_is_public'),
"profile.nameIsPublic" => 'Name ist für Mitglieder sichtbar' "profile.nameIsPublic" => I18n.t('model.user.notify.name_is_public')
} }
end end
# retuns the default setting for a NEW user # retuns the default setting for a NEW user
@ -132,7 +132,7 @@ class User < ActiveRecord::Base
end end
def ordergroup_name def ordergroup_name
ordergroup ? ordergroup.name : "keine Bestellgruppe" ordergroup ? ordergroup.name : I18n.t('model.user.no_ordergroup')
end end
# returns true if user is a member of a given group # returns true if user is a member of a given group

View file

@ -15,7 +15,8 @@ class Workgroup < Group
before_destroy :check_last_admin_group before_destroy :check_last_admin_group
def self.weekdays def self.weekdays
[["Montag", "1"], ["Dienstag", "2"], ["Mittwoch","3"],["Donnerstag","4"],["Freitag","5"],["Samstag","6"],["Sonntag","0"]] days = I18n.t('date.day_names')
(0..days.length-1).map {|i| [days[i], i.to_s]}
end end
# Returns an Array with date-objects to represent the next weekly-tasks # Returns an Array with date-objects to represent the next weekly-tasks
@ -55,7 +56,7 @@ class Workgroup < Group
# Check before destroy a group, if this is the last group with admin role # Check before destroy a group, if this is the last group with admin role
def check_last_admin_group def check_last_admin_group
if role_admin && Workgroup.where(:role_admin => true).size == 1 if role_admin && Workgroup.where(:role_admin => true).size == 1
raise "Die letzte Gruppe mit Admin-Rechten darf nicht gelöscht werden" raise I18n.t('workgroups.error_last_admin_group')
end end
end end
@ -63,7 +64,7 @@ class Workgroup < Group
# Return an error if this is the last group with admin role and role_admin should set to false # Return an error if this is the last group with admin role and role_admin should set to false
def last_admin_on_earth def last_admin_on_earth
if !role_admin && !Workgroup.where('role_admin = ? AND id != ?', true, id).exists? if !role_admin && !Workgroup.where('role_admin = ? AND id != ?', true, id).exists?
errors.add(:role_admin, "Der letzten Gruppe mit Admin-Rechten darf die Admin-Rolle nicht entzogen werden") errors.add(:role_admin, I18n.t('workgroups.error_last_admin_role'))
end end
end end

View file

@ -1,43 +1,43 @@
- title "Administration" - title t '.title'
%p %p
%i Hier kannst Du die Gruppen und Benutzerinnen der Foodsoft verwalten. %i= t '.first_paragraph'
.row-fluid .row-fluid
.span6 .span6
%section %section
%h2 Neuste Benutzerinnen %h2= t '.newest_users'
%table.table.table-striped %table.table.table-striped
%thead %thead
%tr %tr
%th Benutzername %th= t '.username'
%th Name %th= t '.name'
%th Erstellt am %th= t '.created_at'
- for user in @users - for user in @users
%tr{:class => cycle('even','odd', :name => 'users')} %tr{:class => cycle('even','odd', :name => 'users')}
%td= link_to user.nick, [:admin, user] %td= link_to user.nick, [:admin, user]
%td=h user.name %td=h user.name
%td= format_date(user.created_on) %td= format_date(user.created_on)
= link_to 'Alle Benutzerinnen', admin_users_path = link_to t('.all_users'), admin_users_path
| |
= link_to "Neue Benutzerin", new_admin_user_path, class: 'btn btn-primary btn-small' = link_to t('.new_user'), new_admin_user_path, class: 'btn btn-primary btn-small'
.span6 .span6
%section %section
%h2 Neuste Gruppen %h2= t '.newest_groups'
%table.table.table-striped %table.table.table-striped
%thead %thead
%tr %tr
%th Gruppenname %th= t '.groupname'
%th Typ %th= t '.type'
%th Mitglieder %th= t '.members'
- for group in @groups - for group in @groups
%tr{:class => cycle('even','odd', :name => 'groups')} %tr{:class => cycle('even','odd', :name => 'groups')}
%td= link_to group.name, [:admin, group] %td= link_to group.name, [:admin, group]
%td= group.class.model_name.human %td= group.class.model_name.human
%td= group.users.size %td= group.users.size
= link_to 'Alle Bestellgruppen', admin_ordergroups_path = link_to t('.all_ordergroups'), admin_ordergroups_path
| |
= link_to "Neue Bestellgruppe", new_admin_ordergroup_path, class: 'btn btn-primary btn-small' = link_to t('.new_ordergroup'), new_admin_ordergroup_path, class: 'btn btn-primary btn-small'
| |
= link_to 'Alle Arbeitsgruppen', admin_workgroups_path = link_to t('.all_workgroups'), admin_workgroups_path
| |
= link_to "Neue Arbeitsgruppe", new_admin_workgroup_path, class: 'btn btn-primary btn-small' = link_to t('.new_workgroup'), new_admin_workgroup_path, class: 'btn btn-primary btn-small'

View file

@ -1,8 +1,5 @@
- unless @ordergroup.new_record? - unless @ordergroup.new_record?
%p %p= t('.first_paragraph', url: link_to(t('.here'), new_invite_path(id: @ordergroup.id), remote: true)).html_safe
Neue Mitglieder kannst du
= link_to "hier", new_invite_path(id: @ordergroup.id), remote: true
einladen.
= simple_form_for [:admin, @ordergroup] do |f| = simple_form_for [:admin, @ordergroup] do |f|
= render :layout => 'shared/group_form_fields', :locals => {:f => f} do = render :layout => 'shared/group_form_fields', :locals => {:f => f} do
= f.input :contact_person = f.input :contact_person
@ -11,4 +8,4 @@
= f.input :ignore_apple_restriction = f.input :ignore_apple_restriction
.form-actions .form-actions
= f.button :submit = f.button :submit
= link_to "oder abbrechen", :back = link_to t('ui.or_cancel'), :back

View file

@ -4,11 +4,11 @@
%table.table.table-striped %table.table.table-striped
%thead %thead
%tr %tr
%th Name %th= t '.name'
%th Kontakt %th= t '.contact'
%th Adresse %th= t '.address'
%th Mitglieder %th= t '.members'
%th Aktionen %th= t 'admin.actions'
%tbody %tbody
- for ordergroup in @ordergroups - for ordergroup in @ordergroups
%tr{:class => cycle('even','odd', :name => 'groups')} %tr{:class => cycle('even','odd', :name => 'groups')}
@ -17,6 +17,6 @@
%td= link_to_gmaps ordergroup.contact_address %td= link_to_gmaps ordergroup.contact_address
%td= ordergroup.users.size %td= ordergroup.users.size
%td %td
= link_to "Bearbeiten", edit_admin_ordergroup_path(ordergroup), class: 'btn btn-mini' = link_to t('ui.edit'), edit_admin_ordergroup_path(ordergroup), class: 'btn btn-mini'
= link_to "Löschen", [:admin, ordergroup], :confirm => "Willst du #{ordergroup.name} wirklich löschen?", = link_to t('ui.delete'), [:admin, ordergroup], :confirm => t('admin.confirm', name: ordergroup.name),
:method => :delete, class: 'btn btn-mini btn-danger' :method => :delete, class: 'btn btn-mini btn-danger'

View file

@ -1,3 +1,3 @@
- title "Bestellgruppe bearbeiten" - title t '.title'
= render :partial => 'form' = render 'form'

View file

@ -1,25 +1,15 @@
- title "Bestellgruppen" - title t('.title')
- content_for :actionbar do - content_for :actionbar do
= link_to "Neue Bestellgruppe anlegen", new_admin_ordergroup_path, class: 'btn btn-primary' = link_to t('.new_ordergroup'), new_admin_ordergroup_path, class: 'btn btn-primary'
- content_for :sidebar do - content_for :sidebar do
%p %p= t('.first_paragraph', url: link_to(t('.new_ordergroups'), new_admin_ordergroup_path)).html_safe
Hier kannst du %p= t('.second_paragraph', url: link_to(t('.workgroup'), admin_workgroups_path)).html_safe
= link_to 'neue Bestellgruppen', new_admin_ordergroup_path
anlegen, Gruppen bearbeiten und löschen.
%p
Beachte dabei den <em>Unterschied zwischen Gruppe und Bestellgruppe</em>:
Eine Bestellgruppe hat ein Konto und kann Essen bestellen. In einer
%em= link_to 'Arbeitsgruppe', admin_workgroups_path
(z.b. 'Soritiergruppe')
koordinieren sich die Mitglieder mittels Aufgaben und Nachrichten.
Nutzer_innen können immer nur einer Bestellgruppe, aber beliebig vielen anderen Gruppen angehören.
.well.well-small .well.well-small
= form_tag admin_ordergroups_path, :method => :get, :remote => true, = form_tag admin_ordergroups_path, :method => :get, :remote => true,
'data-submit-onchange' => true, class: 'form-search' do 'data-submit-onchange' => true, class: 'form-search' do
= text_field_tag :query, params[:query], class: 'input-medium search-query', = text_field_tag :query, params[:query], class: 'input-medium search-query',
placeholder: 'Name ...' placeholder: t('admin.search_placeholder')
#ordergroups #ordergroups
= render "ordergroups" = render "ordergroups"

View file

@ -1,3 +1,3 @@
- title "Bestellgruppe anlegen" - title t '.title'
= render 'form' = render 'form'

View file

@ -1,6 +1,6 @@
- title "Bestellgruppe #{@ordergroup.name}" - title t '.title', name: @ordergroup.name
%section= render 'shared/group', group: @ordergroup %section= render 'shared/group', group: @ordergroup
= link_to 'Gruppe/Mitglieder bearbeiten', edit_admin_ordergroup_path(@ordergroup), class: 'btn' = link_to t('ui.edit'), edit_admin_ordergroup_path(@ordergroup), class: 'btn'
= link_to 'Löschen', [:admin, @ordergroup], :confirm => 'Bist Du sicher?', :method => :delete, class: 'btn btn-danger' = link_to t('ui.delete'), [:admin, @ordergroup], :confirm => t('.confirm'), :method => :delete, class: 'btn btn-danger'
= link_to 'Nachricht senden', new_message_path(:message => {:group_id => @ordergroup.id}), class: 'btn' = link_to t('.send_message'), new_message_path(:message => {:group_id => @ordergroup.id}), class: 'btn'

View file

@ -1,5 +1,5 @@
= simple_form_for([:admin, @user]) do |f| = simple_form_for([:admin, @user]) do |f|
= render :partial => 'shared/user_form_fields', :locals => {:f => f} = render 'shared/user_form_fields', f: f
.form-actions .form-actions
= f.submit = f.submit
= link_to 'oder abbrechen', :back = link_to t('ui.or_cancel'), :back

View file

@ -4,12 +4,12 @@
%table.table.table-striped %table.table.table-striped
%thead %thead
%tr %tr
%th Login %th= t '.login'
%th Name %th= t '.name'
%th Email %th= t '.email'
%th Zugriff auf %th= t 'admin.access_to'
%th Letzter login %th= t '.last_login'
%th(colspan="2") Aktionen %th(colspan="2")= t 'admin.actions'
%tbody %tbody
- for user in @users - for user in @users
%tr %tr
@ -18,6 +18,6 @@
%td= user.email %td= user.email
%td= format_roles(user) %td= format_roles(user)
%td= format_time(user.last_login) %td= format_time(user.last_login)
%td= link_to 'Bearbeiten', edit_admin_user_path(user), class: 'btn btn-mini' %td= link_to t('ui.edit'), edit_admin_user_path(user), class: 'btn btn-mini'
%td= link_to 'Löschen', [:admin, user], :confirm => "Willst du #{user.name} wirklich löschen?", %td= link_to t('ui.delete'), [:admin, user], :confirm => t('admin.confirm', name: user.name),
:method => :delete, class: 'btn btn-danger btn-mini' :method => :delete, class: 'btn btn-danger btn-mini'

View file

@ -1,3 +1,3 @@
- title "Benutzerin bearbeiten" - title t '.title'
= render 'form' = render 'form'

View file

@ -1,18 +1,16 @@
- title "Admin/Benutzerinnen" - title t '.title'
- content_for :actionbar do - content_for :actionbar do
= link_to 'Neue Benutzerin anlegen', new_admin_user_path, class: 'btn btn-primary' = link_to t('.new_user'), new_admin_user_path, class: 'btn btn-primary'
- content_for :sidebar do - content_for :sidebar do
%p %p= t('.first_paragraph', url: link_to(t('.new_users'), new_admin_user_path)).html_safe
Hier kannst du Benutzer_innen #{link_to 'neu Anlegen', new_admin_user_path},
bearbeiten und natürlich auch löschen.
.well.well-small .well.well-small
= form_tag admin_users_path, :method => :get, :remote => true, = form_tag admin_users_path, :method => :get, :remote => true,
'data-submit-onchange' => true, class: 'form-search' do 'data-submit-onchange' => true, class: 'form-search' do
= text_field_tag :user_name, params[:user_name], class: 'input-medium search-query', = text_field_tag :user_name, params[:user_name], class: 'input-medium search-query',
placeholder: 'Name ...' placeholder: t('admin.search_placeholder')
#users #users
= render "users" = render "users"

View file

@ -1,3 +1,3 @@
- title "Neue Benutzerin anlegen" - title t '.title'
= render 'form' = render 'form'

View file

@ -3,37 +3,37 @@
.row-fluid .row-fluid
.span3 .span3
.well .well
%h4 Person %h4= t '.person'
%p Mitglied seit #{distance_of_time_in_words(Time.now, @user.created_on)} %p= t '.member_since', time: distance_of_time_in_words(Time.now, @user.created_on)
%dl %dl
%dt Nick %dt= t '.nick'
%dd= @user.nick %dd= @user.nick
%dt Name %dt= t '.name'
%dd= h @user.name %dd= h @user.name
%dt Email %dt= t '.email'
%dd= @user.email %dd= @user.email
%dt Telefon %dt= t '.phone'
%dd= @user.phone %dd= @user.phone
%dt Zugriff auf %dt= t 'admin.access_to'
%dd= format_roles(@user) %dd= format_roles(@user)
.span5 .span5
.well .well
%h4 Einstellungen %h4= t '.preference'
%table.table %table.table
- for setting in User::setting_keys.keys - for setting in User::setting_keys.keys
%tr %tr
%td= User::setting_keys[setting] %td= User::setting_keys[setting]
%td= @user.settings[setting] == '1' ? 'ja' : 'nein' %td= @user.settings[setting] == '1' ? t('simple_form.yes') : t('simple_form.no')
.span3 .span3
.well .well
%h4 Gruppenabos %h4= t '.groupabos'
%ul.unstyled %ul.unstyled
- for membership in Membership.find_all_by_user_id(@user.id) - for membership in Membership.find_all_by_user_id(@user.id)
%li= link_to(membership.group.name, [:admin, membership.group]) %li= link_to(membership.group.name, [:admin, membership.group])
%hr/ %hr/
%p %p
= link_to 'Bearbeiten', edit_admin_user_path(@user), class: 'btn' = link_to t('ui.edit'), edit_admin_user_path(@user), class: 'btn'
= link_to 'Löschen', [:admin, @user], :confirm => "Willst du #{@user.first_name} wirklich rausschmeißen?", = link_to t('ui.delete'), [:admin, @user], :confirm => t('.confirm', user: @user.first_name),
:method => :delete, class: 'btn btn-danger' :method => :delete, class: 'btn btn-danger'
= link_to "Nachricht senden", new_message_path(:message => {:mail_to => @user.id}), class: 'btn' = link_to t('.send_message'), new_message_path(:message => {:mail_to => @user.id}), class: 'btn'

View file

@ -1,10 +1,7 @@
%p %p= t('.first_paragraph', url: link_to(t('.here'), new_invite_path(id: @workgroup.id), remote: true)).html_safe
Neue Mitglieder kannst du
= link_to "hier", new_invite_path(id: @workgroup.id)
einladen.
= simple_form_for [:admin, @workgroup] do |f| = simple_form_for [:admin, @workgroup] do |f|
= render :layout => 'shared/group_form_fields', :locals => {:f => f} do = render :layout => 'shared/group_form_fields', :locals => {:f => f} do
%h4 Zugriff auf %h4= t 'admin.access_to'
= f.input :role_admin = f.input :role_admin
= f.input :role_finance = f.input :role_finance
= f.input :role_suppliers = f.input :role_suppliers
@ -12,4 +9,4 @@
= f.input :role_orders = f.input :role_orders
.form-actions .form-actions
= f.button :submit = f.button :submit
= link_to "oder abbrechen", :back = link_to t('ui.or_cancel'), :back

View file

@ -4,10 +4,10 @@
%table.table.table-striped %table.table.table-striped
%thead %thead
%tr %tr
%th Name %th= t '.name'
%th Mitglieder %th= t '.members'
%th Zugriff auf %th= t 'admin.access_to'
%th Aktionen %th= t 'admin.actions'
%tbody %tbody
- for workgroup in @workgroups - for workgroup in @workgroups
%tr %tr
@ -15,6 +15,6 @@
%td= workgroup.users.size %td= workgroup.users.size
%td= format_roles(workgroup) %td= format_roles(workgroup)
%td %td
= link_to "Bearbeiten", edit_admin_workgroup_path(workgroup), class: 'btn btn-mini' = link_to t('ui.edit'), edit_admin_workgroup_path(workgroup), class: 'btn btn-mini'
= link_to "Löschen", [:admin, workgroup], :confirm => 'Willst du ' + workgroup.name + ' wirklich löschen?', = link_to t('ui.delete'), [:admin, workgroup], :confirm => t('admin.confirm', name: workgroup.name),
:method => :delete, class: 'btn btn-mini btn-danger' :method => :delete, class: 'btn btn-mini btn-danger'

View file

@ -1,3 +1,3 @@
- title "Arbeitsgruppe bearbeiten" - title t '.title'
= render 'form' = render 'form'

View file

@ -1,24 +1,15 @@
- title "Arbeitsgruppen" - title t '.title'
- content_for :actionbar do - content_for :actionbar do
= link_to "Neue Arbeitsgruppe anlegen", new_admin_workgroup_path, class: 'btn btn-primary' = link_to t('.new_workgroup'), new_admin_workgroup_path, class: 'btn btn-primary'
- content_for :sidebar do - content_for :sidebar do
%p %p= t('.first_paragraph', url: link_to(t('.new_workgroups'), new_admin_workgroup_path)).html_safe
Hier kannst du %p= t('.second_paragraph', url: link_to(t('.ordergroup'), admin_ordergroups_path)).html_safe
= link_to 'neue Arbeitsgruppen', new_admin_workgroup_path
anlegen, Gruppen bearbeiten und löschen.
%p
Beachte dabei den <strong>Unterschied zwischen Gruppe und Bestellgruppe</strong>:
Eine #{link_to 'Bestellgruppe', '/admin/ordergroups'}
hat ein Konto und kann Essen bestellen. In einer Arbeitsgruppe (z.b. 'Soritiergruppe')
koordinieren sich die Mitglieder mittels Aufgaben und Nachrichten.
Nutzer_innen können immer nur einer Bestellgruppe, aber beliebig vielen anderen Gruppen angehören.
.well.well-small .well.well-small
= form_tag admin_workgroups_path, :method => :get, :remote => true, = form_tag admin_workgroups_path, :method => :get, :remote => true,
'data-submit-onchange' => true, class: 'form-search' do 'data-submit-onchange' => true, class: 'form-search' do
= text_field_tag :query, params[:query], class: 'input-medium search-query', = text_field_tag :query, params[:query], class: 'input-medium search-query',
placeholder: 'Name ...' placeholder: t('admin.search_placeholder')
#workgroups #workgroups
= render "workgroups" = render "workgroups"

View file

@ -1,3 +1,3 @@
- title "Arbeitsgruppe anlegen" - title t '.title'
= render 'form' = render 'form'

View file

@ -1,6 +1,6 @@
- title "Arbeitsgruppe #{@workgroup.name}" - title t '.title', name: @workgroup.name
%section= render :partial => 'shared/group', :locals => { :group => @workgroup } %section= render 'shared/group', group: @workgroup
= link_to 'Gruppe/Mitglieder bearbeiten', edit_admin_workgroup_path(@workgroup), class: 'btn' = link_to t('ui.edit'), edit_admin_workgroup_path(@workgroup), class: 'btn'
= link_to 'Löschen', [:admin, @workgroup], :confirm => 'Bist Du sicher?', :method => :delete, class: 'btn btn-danger' = link_to t('ui.delete'), [:admin, @workgroup], :confirm => t('.confirm'), :method => :delete, class: 'btn btn-danger'
= link_to_new_message(message_params: {group_id: @workgroup.id}) = link_to_new_message(message_params: {group_id: @workgroup.id})

View file

@ -3,4 +3,4 @@
= f.input :description = f.input :description
.form-actions .form-actions
= f.submit class: 'btn' = f.submit class: 'btn'
= link_to 'oder abbrechen', article_categories_path = link_to t('ui.or_cancel'), article_categories_path

View file

@ -1,3 +1,3 @@
- title "Kategorie ändern" - title t('.title')
= render 'form' = render 'form'

View file

@ -1,12 +1,12 @@
- title "Artikelkategorien" - title t('.title')
%p= link_to "Neue Kategorie anlegen", new_article_category_path, class: 'btn btn-primary' %p= link_to t('.new'), new_article_category_path, class: 'btn btn-primary'
%table.table.table-striped %table.table.table-striped
%thead %thead
%tr %tr
%th Name %th= t('simple_form.labels.article_category.name')
%th Beschreibung %th= t('simple_form.labels.article_category.description')
%th %th
%tbody %tbody
- @article_categories.each do |article_category| - @article_categories.each do |article_category|
@ -14,6 +14,6 @@
%td= article_category.name %td= article_category.name
%td= article_category.description %td= article_category.description
%td %td
= link_to "Bearbeiten", edit_article_category_path(article_category), class: 'btn btn-mini' = link_to t('ui.edit'), edit_article_category_path(article_category), class: 'btn btn-mini'
= link_to "Löschen", article_category, :method => :delete, :confirm => 'Are you sure?', = link_to t('ui.delete'), article_category, :method => :delete, :confirm => t('.confirm_delete'),
class: 'btn btn-mini btn-danger' class: 'btn btn-mini btn-danger'

View file

@ -1,3 +1,3 @@
- title "Neue Kategorie anlegen" - title t('.title')
= render 'form' = render 'form'

View file

@ -7,11 +7,11 @@
%td= truncate(article.note, :length => 11) %td= truncate(article.note, :length => 11)
%td= article.unit_quantity %td= article.unit_quantity
%td{:class => "currency"} %td{:class => "currency"}
%acronym{:title => "zuletzt geändert: #{format_date(article.updated_at)} | Brutto: #{number_to_currency(article.gross_price)}"} %acronym{:title => t('.last_update', last_update: format_date(article.updated_at), gross_price: number_to_currency(article.gross_price))}
= 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= link_to "Bearbeiten", edit_supplier_article_path(@supplier, article), %td= link_to t('ui.edit'), edit_supplier_article_path(@supplier, article),
:remote => true, class: 'btn btn-mini' :remote => true, class: 'btn btn-mini'
%td= link_to "Löschen", [@supplier, article], %td= link_to t('ui.delete'), [@supplier, article],
:method => :delete, :confirm => 'Bist du sicher?', :remote => true, class: 'btn btn-mini btn-danger' :method => :delete, :confirm => t('.confirm_delete'), :remote => true, class: 'btn btn-mini btn-danger'

View file

@ -6,15 +6,16 @@
%thead %thead
%tr %tr
%th %th
%th= sort_link_helper "Name", "name" %th= sort_link_helper t('simple_form.labels.article.name'), "name"
%th %th
%th= sort_link_helper "Kategorie", "category" %th= sort_link_helper t('simple_form.labels.article.article_category'), "category"
%th= sort_link_helper "Einheit", "unit" %th= sort_link_helper t('simple_form.labels.article.unit'), "unit"
%th= sort_link_helper "Notiz", "note" %th= sort_link_helper t('simple_form.labels.article.note'), "note"
%th{:style => "width: 4em;"} Gebgr. %th{:style => "width: 4em;"}
%th{:style => "width: 5em;"} Preis %acronym{:title => t('.unit_quantity_desc')}= t '.unit_quantity_short'
%th{:style => "width: 3.5em;"} MwSt %th{:style => "width: 5em;"}= t '.price_netto'
%th{:style => "width: 4em;"} Pfand %th{:style => "width: 3.5em;"}= t 'simple_form.labels.defaults.tax'
%th{:style => "width: 4em;"}= t 'simple_form.labels.defaults.deposit'
%th{:style => "width: 3em;"} %th{:style => "width: 3em;"}
%tbody#listbody %tbody#listbody
@ -27,10 +28,10 @@
%td{:colspan => '11'} %td{:colspan => '11'}
= check_box_tag :checkall, 1, false, 'data-check-all' => '#articlesInListForm', 'data-ignore-onchange' => true = check_box_tag :checkall, 1, false, 'data-check-all' => '#articlesInListForm', 'data-ignore-onchange' => true
%select{:name => "selected_action", 'data-submit-onchange' => true} %select{:name => "selected_action", 'data-submit-onchange' => true}
%option{:value => '', :selected => 'selected'} Aktion wählen ... %option{:value => '', :selected => 'selected'}= t '.option_select'
%option{:value => "destroy", 'data-confirm' => 'Willst Du wirklich alle gewählten Artikel löschen?'} Artikel löschen %option{:value => "destroy", 'data-confirm' => t('.confirm_delete')}= t '.option_delete'
%option{:value => "setNotAvailable"} Artikel sind nicht mehr verfügbar %option{:value => "setNotAvailable"}= t '.option_not_available'
%option{:value => "setAvailable"} Artikel sind verfügbar %option{:value => "setAvailable"}= t '.option_available'
= hidden_field_tag 'supplier_id', @supplier.id = hidden_field_tag 'supplier_id', @supplier.id
= pagination_links_remote @articles = pagination_links_remote @articles

View file

@ -1,7 +1,3 @@
%tr.edit_inline{:id=> "edit_"+@article.id.to_s} %tr.edit_inline{:id=> "edit_"+@article.id.to_s}
%td{:colspan=>"10"} %td{:colspan=>"10"}
=h @article.name = t('.note', article: h(@article.name), drop_link: link_to(t('.drop'), :controller => 'orders', :action => 'edit', :id => @order)).html_safe
wird in laufenden Bestellungen verwendet und kann nicht gelöscht werden.
Bitte zuerst den Artikel aus den Bestellungen
= link_to "entfernen", :controller => 'orders', :action => 'edit', :id => @order

View file

@ -2,18 +2,19 @@
%thead %thead
%tr %tr
%th %th
%acronym{:title => "verfügbar"} verf. %acronym{:title => t('.available_desc')}= t '.available_short'
%th Name %th= t 'simple_form.labels.article.name'
%th Einheit %th= t 'simple_form.labels.article.unit'
%th %th
%acronym{:title => "Netto!"} Preis %acronym{:title => t('.price_desc')}= t '.price_short'
%th %th
%acronym{:title => "Gebindegröße"} GebGr %acronym{:title => t('.unit_quantity_desc')}= t '.unit_quantity_short'
%th Best.Nr. %th
%th Notiz %acronym{:title => t('.order_number_desc')}= t '.order_number_short'
%th Kategorie %th= t 'simple_form.labels.article.note'
%th MwSt. %th= t 'simple_form.labels.article.article_category'
%th Pfand %th= t 'simple_form.labels.defaults.tax'
%th= t 'simple_form.labels.defaults.deposit'
%tbody %tbody
- @articles.each_with_index do |article, index| - @articles.each_with_index do |article, index|
= fields_for "articles[#{article.id || index}]", article do |form| = fields_for "articles[#{article.id || index}]", article do |form|

View file

@ -2,8 +2,8 @@
= f.hidden_field :shared_updated_on = f.hidden_field :shared_updated_on
= f.hidden_field :supplier_id = f.hidden_field :supplier_id
.modal-header .modal-header
= button_tag "x", class: 'close', data: {dismiss: 'modal'} = link_to t('ui.marks.close').html_safe, '#', class: 'close', data: {dismiss: 'modal'}
%h3 Neuen Artikel einfügen %h3= t '.title'
.modal-body .modal-body
= f.input :availability = f.input :availability
= f.input :name = f.input :name
@ -19,6 +19,6 @@
= f.input :tax = f.input :tax
= f.input :deposit = f.input :deposit
.modal-footer .modal-footer
= button_tag "Schließen", class: 'btn', data: {dismiss: 'modal'} = link_to t('ui.close'), '#', class: 'btn', data: {dismiss: 'modal'}
= f.submit class: 'btn btn-primary' = f.submit class: 'btn btn-primary'

View file

@ -1,17 +1,17 @@
- if @articles.empty? - if @articles.empty?
%p Keine Artikel gefunden %p= t '.not_found'
- else - else
= pagination_links_remote @articles, :params => {:search => search_params} = pagination_links_remote @articles, :params => {:search => search_params}
%table.table.table-striped %table.table.table-striped
%thead %thead
%tr %tr
%th Name %th= t 'simple_form.labels.article.name'
%th Herkunft %th= t 'simple_form.labels.article.origin'
%th Hersteller %th= t 'simple_form.labels.article.manufacturer'
%th Notiz %th= t 'simple_form.labels.article.note'
%th{:style => "width:4em"} Preis %th{:style => "width:4em"}= t 'simple_form.labels.defaults.price'
%th Einheit %th= t 'simple_form.labels.article.unit'
%th GebGröße %th= t 'simple_form.labels.defaults.unit_quantity'
%th %th
%tbody %tbody
- for article in @articles - for article in @articles
@ -25,9 +25,8 @@
%td= article.unit_quantity %td= article.unit_quantity
%td %td
- logger.debug "[debug] #{article.attributes.inspect}" - logger.debug "[debug] #{article.attributes.inspect}"
- if @supplier.articles.where(order_number: article.number).exists? - if @supplier.articles.undeleted.where(order_number: article.number).exists?
%i.icon-ok %i.icon-ok= t '.already_imported'
schon importiert
- else - else
= link_to 'importieren', import_supplier_articles_path(@supplier, :shared_article_id => article.id), = link_to t('.action_import'), import_supplier_articles_path(@supplier, :shared_article_id => article.id),
:remote => true, class: 'btn btn-small btn-success' :remote => true, class: 'btn btn-small btn-success'

View file

@ -1,11 +1,10 @@
- title "Alle Artikel von #{@supplier.name} bearbeiten" | - title t('.title', supplier: @supplier.name)
%p %p
%i %i= t '.note'
Pflichtfelder sind: Name, Einheit, (netto) Preis und Bestellnummer.
= form_tag(update_all_supplier_articles_path(@supplier)) do = form_tag(update_all_supplier_articles_path(@supplier)) do
= render 'edit_all_table' = render 'edit_all_table'
%br/ %br/
%i Achtung, alle Artikel werden aktualisiert! %i= t '.warning'
.form-actions .form-actions
= submit_tag 'Alle Artikel aktualisieren', class: 'btn btn-primary' = submit_tag t('.submit'), class: 'btn btn-primary'
= link_to 'oder abbrechen', supplier_articles_path(@supplier) = link_to t('ui.or_cancel'), supplier_articles_path(@supplier)

View file

@ -1,47 +1,48 @@
- title "Artikel von #{@supplier.name} (#{@supplier.articles.count})" - title t('.title', supplier: @supplier.name, count: @supplier.articles.undeleted.count)
.well.well-small .well.well-small
.btn-toolbar .btn-toolbar
= form_tag supplier_articles_path(@supplier), method: :get, remote: true, class: 'form-search pull-right', = form_tag supplier_articles_path(@supplier), method: :get, remote: true, class: 'form-search pull-right',
'data-submit-onchange' => true do 'data-submit-onchange' => true do
= text_field_tag :query, params[:query], class: 'input-medium search-query', = text_field_tag :query, params[:query], class: 'input-medium search-query',
placeholder: 'Name ...' placeholder: t('.search_placeholder')
.btn-group .btn-group
= link_to "Neuer Artikel", new_supplier_article_path(@supplier), remote: true, class: 'btn btn-primary' = link_to t('.new'), new_supplier_article_path(@supplier), remote: true, class: 'btn btn-primary'
= link_to "Alle bearbeiten", edit_all_supplier_articles_path(@supplier), class: 'btn' = link_to t('.edit_all'), edit_all_supplier_articles_path(@supplier), class: 'btn'
= link_to "Artikel hochladen", upload_supplier_articles_path(@supplier), class: 'btn' = link_to t('.upload'), upload_supplier_articles_path(@supplier), class: 'btn'
- if current_user.role_orders? - if current_user.role_orders?
= link_to "Bestellung anlegen", new_order_path(supplier_id: @supplier), class: 'btn' = link_to t('.new_order'), new_order_path(supplier_id: @supplier), class: 'btn'
- unless @supplier.shared_supplier.nil? - unless @supplier.shared_supplier.nil?
.btn-group .btn-group
= link_to '#', data: {toggle: 'dropdown'}, class: 'btn btn-success dropdown-toggle' do = link_to '#', data: {toggle: 'dropdown'}, class: 'btn btn-success dropdown-toggle' do
Externe Datenbank = t '.ext_db.title'
%span.caret %span.caret
%ul.dropdown-menu %ul.dropdown-menu
%li= link_to "Suchen/Importieren", "#import", 'data-toggle-this' => '#import' %li= link_to t('.ext_db.import'), "#import", 'data-toggle-this' => '#import'
%li= link_to "Synchronisieren", sync_supplier_articles_path(@supplier), method: :post %li= link_to t('.ext_db.sync'), sync_supplier_articles_path(@supplier), method: :post
.btn-group .btn-group
= link_to '#', data: {toggle: 'dropdown'}, class: 'btn dropdown-toggle' do = link_to '#', data: {toggle: 'dropdown'}, class: 'btn dropdown-toggle' do
Lieferant wechseln .. = t '.change_supplier'
%span.caret %span.caret
%ul.dropdown-menu %ul.dropdown-menu
- Supplier.where('id != ?', @supplier.id).order('name ASC').each do |supplier| - Supplier.undeleted.where('id != ?', @supplier.id).order('suppliers.name ASC').each do |supplier|
%li= link_to supplier.name, supplier_articles_path(supplier), tabindex: -1 %li= link_to supplier.name, supplier_articles_path(supplier), tabindex: -1
- unless @supplier.shared_supplier.nil? - unless @supplier.shared_supplier.nil?
#import.well.well-small(style="display:none;") #import.well.well-small(style="display:none;")
= form_tag shared_supplier_articles_path(@supplier), method: :get, remote: true, class: 'form-search', = form_tag shared_supplier_articles_path(@supplier), method: :get, remote: true, class: 'form-search',
'data-submit-onchange' => true do 'data-submit-onchange' => true do
%h3 Artikel importieren %h3= t '.import.title'
= text_field_tag "search[name_contains_all]", "", class: 'input-medium search-query', placeholder: 'Name ...' = text_field_tag "search[name_contains_all]", "", class: 'input-medium search-query',
placeholder: t('.import.placeholder')
%label.checkbox %label.checkbox
= check_box_tag "search[origin_equals]", "REG", false = check_box_tag "search[origin_equals]", "REG", false
Nur aus der Region = t '.import.restrict_region'
#search_results.clearfix #search_results.clearfix
= link_to "Schließen", "#import", 'data-toggle-this' => '#import' = link_to t('ui.close'), "#import", 'data-toggle-this' => '#import'
= form_tag update_selected_supplier_articles_path(@supplier), id: "articlesInListForm", = form_tag update_selected_supplier_articles_path(@supplier), id: "articlesInListForm",
'data-submit-onchange' => true do 'data-submit-onchange' => true do

View file

@ -1,13 +1,9 @@
- title "#{@supplier.name} / Artikel hochladen" - title t('.title', supplier: @supplier.name)
%p %p= t('.body').html_safe
%i
Bitte überprüfe die eingelesenen Artikel.
%br/
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
= render 'edit_all_table' = render 'edit_all_table'
.form-actions .form-actions
= submit_tag "Speichere neue Artikel für #{@supplier.name}", class: 'btn btn-primary' = submit_tag t('.submit', supplier: @supplier.name), class: 'btn btn-primary'
= link_to "order abbrechen", upload_supplier_articles_path(@supplier) = link_to t('ui.or_cancel'), upload_supplier_articles_path(@supplier)

View file

@ -1,44 +1,43 @@
%h1 Artikel mit externer Datenbank synchronisieren - title 'Artikel mit externer Datenbank synchronisieren'
- form_tag update_all_supplier_articles_path(@supplier, :sync => "1") do = form_tag update_synchronized_supplier_articles_path(@supplier) do
%h2 Auslisten ... %h2= t '.outlist.title'
%p %p
- unless @outlisted_articles.empty? - unless @outlisted_articles.empty?
Folgende Artikel wurden ausgelistet und werden = t('.outlist.body').html_safe
%b gelöscht:
%ul %ul
- for article in @outlisted_articles - for article in @outlisted_articles
%li %li
= hidden_field_tag "outlisted_articles[#{article.id}]", '1' = hidden_field_tag "outlisted_articles[#{article.id}]", '1'
= article.name = article.name
- if article.in_open_order
.alert
Achtung, #{article.name} wird gerade in einer laufenden Bestellung verwendet. Bitte erst Bestellung anpassen.
- else - else
%i Es müssen keine Artikel gelöscht werden. %i= t '.outlist.body_skip'
%hr/ %hr/
%h2 Aktualisieren ... %h2= t '.update.title'
%p %p
%i %i
%b= @updated_articles.size %b= @updated_articles.size
Artikel müssen aktualisiert werden: = t '.update.update_msg'
%p = t('.update.body').html_safe
%i %table.table
Jeder Artikel wird doppelt angezeigt. Die alten Werte sind grau und die Textfelder sind mit den aktuellen %thead
Werten vorausgefüllt.
%br/
Abweichungen zu den alten Artikeln sind gelb markiert.
%table
%tr %tr
%th Name %th= t 'simple_form.labels.article.name'
%th Notiz %th= t 'simple_form.labels.article.note'
%th Hersteller %th= t 'simple_form.labels.article.manufacturer'
%th Herkunft %th= t 'simple_form.labels.article.origin'
%th Einheit %th= t 'simple_form.labels.article.unit'
%th GebGr %th= t '.unit_quantity_short'
%th Preis %th= t '.price_short'
%th MwSt. %th= t 'simple_form.labels.defaults.tax'
%th Pfand %th= t 'simple_form.labels.defaults.deposit'
%th Kategorie %th= t 'simple_form.labels.article.article_category'
- @updated_articles.each do |@article, unequal_attributes| %tbody
- article = Article.find(@article.id) - @updated_articles.each do |updated_article, attrs|
- article = Article.find(updated_article.id)
%tr{:style => 'color:grey'} %tr{:style => 'color:grey'}
%td= article.name %td= article.name
%td= article.note %td= article.note
@ -51,21 +50,21 @@
%td= article.deposit %td= article.deposit
%td= article.article_category.name if article.article_category %td= article.article_category.name if article.article_category
%tr %tr
- fields_for 'articles[]', @article do |form| = fields_for 'articles[]', updated_article do |form|
%td{:style => highlight_new(unequal_attributes, :name)} %td{:style => highlight_new(attrs, :name)}
= form.text_field 'name', :size => 0 = form.text_field 'name', :size => 0
= form.hidden_field 'shared_updated_on' = form.hidden_field 'shared_updated_on'
%td{:style => highlight_new(unequal_attributes, :note)}= form.text_field 'note', :size => 15 %td{:style => highlight_new(attrs, :note)}= form.text_field 'note', class: 'input-small'
%td{:style => highlight_new(unequal_attributes, :manufacturer)}= form.text_field 'manufacturer', :size => 10 %td{:style => highlight_new(attrs, :manufacturer)}= form.text_field 'manufacturer', class: 'input-small'
%td{:style => highlight_new(unequal_attributes, :origin)}= form.text_field 'origin', :size => 5 %td{:style => highlight_new(attrs, :origin)}= form.text_field 'origin', class: 'input-mini'
%td{:style => highlight_new(unequal_attributes, :unit)}= form.text_field 'unit', :size => 5 %td{:style => highlight_new(attrs, :unit)}= form.text_field 'unit', class: 'input-mini'
%td{:style => highlight_new(unequal_attributes, :unit_quantity)}= form.text_field 'unit_quantity', :size => 5 %td{:style => highlight_new(attrs, :unit_quantity)}= form.text_field 'unit_quantity', class: 'input-mini'
%td{:style => highlight_new(unequal_attributes, :price)}= form.text_field 'price', :size => 5 %td{:style => highlight_new(attrs, :price)}= form.text_field 'price', class: 'input-mini'
%td{:style => highlight_new(unequal_attributes, :tax)}= form.text_field 'tax', :size => 4 %td{:style => highlight_new(attrs, :tax)}= form.text_field 'tax', class: 'input-mini'
%td{:style => highlight_new(unequal_attributes, :deposit)}= form.text_field 'deposit', :size => 4 %td{:style => highlight_new(attrs, :deposit)}= form.text_field 'deposit', class: 'input-mini'
%td= select 'article[]', 'article_category_id', ArticleCategory.find(:all).collect {|a| [ a.name, a.id ] }, { :include_blank => true } %td= form.select :article_category_id, ArticleCategory.all.map {|a| [ a.name, a.id ] },
{include_blank: true}, class: 'input-small'
%hr/ %hr/
= hidden_field 'supplier', 'id' = hidden_field 'supplier', 'id'
= submit_tag 'Alle löschen/aktualisieren' = submit_tag t('.submit'), class: 'btn btn-primary'
| = link_to t('ui.or_cancel'), supplier_articles_path(@supplier)
= link_to 'Abbrechen', supplier_articles_path(@supplier)

View file

@ -1,21 +1,24 @@
- title "#{@supplier.name} / Artikel hochladen" - title t('.title', supplier: @supplier.name)
%p = t('.body').html_safe
Die Datei muss eine Textdatei mit der Endung '.csv' sein. Die erste Zeile
wird beim Einlesen ignoriert.
%br/
Die Felder müssen mit einem Semikolon (';') getrennt und der Text mit doppelten
Anführungszeichen ("Text...") umklammert werden.
%br/
Als Zeichensatz wird UTF-8 erwartet. Korrekte Reihenfolge der Spalten:
%pre %pre
= ["Status (x=ausgelistet)", "Bestellnummer", "Name", "Notiz", "Hersteller", "Herkunft", = [t('.fields.status'),
"Einheit", "Preis(netto)", "MwSt", "Pfand", "Gebindegröße", t('simple_form.labels.defaults.order_number'),
"Staffelmenge", "Staffelpreis", "Kategorie"].join(" | ") t('simple_form.labels.article.name'),
t('simple_form.labels.article.note'),
t('simple_form.labels.article.manufacturer'),
t('simple_form.labels.article.origin'),
t('simple_form.labels.article.unit'),
t('simple_form.labels.defaults.price'),
t('simple_form.labels.defaults.tax'),
t('simple_form.labels.defaults.deposit'),
t('simple_form.labels.defaults.unit_quantity'),
t('.fields.season_amount'),
t('.fields.season_price'),
t('simple_form.labels.article.article_category')].join(" | ")
= form_for :articles, :url => parse_upload_supplier_articles_path(@supplier), = form_for :articles, :url => parse_upload_supplier_articles_path(@supplier),
:html => { :multipart => true } do |f| :html => { :multipart => true } do |f|
%label(for="articles_file") %label(for="articles_file")= t '.file_label'
Bitte wähle eine kompatible Datei aus
= f.file_field "file" = f.file_field "file"
.form-actions .form-actions
= submit_tag "Datei hochladen", class: 'btn' = submit_tag t('.submit'), class: 'btn'

View file

@ -21,28 +21,24 @@
Menge Menge
= stock_change_form.text_field :quantity, size: 5, autocomplete: 'off' = stock_change_form.text_field :quantity, size: 5, autocomplete: 'off'
= stock_change_form.hidden_field :_destroy = stock_change_form.hidden_field :_destroy
= link_to "Artikel aus Lieferung entfernen", "#", class: 'destroy_stock_change' = link_to t('.remove_article'), "#", class: 'destroy_stock_change'
%p %p
= link_to "Lagerartikel der Lieferung hinzufügen", {action: 'add_stock_change', supplier_id: @supplier.id}, remote: true = link_to t('.add_article'), {action: 'add_stock_change', supplier_id: @supplier.id}, remote: true
%p %p
%small %small= t('.note_new_article', new_link: link_to(t('.note_new_article_link'), new_stock_article_path)).html_safe
Ist ein Artikel noch nicht in der Lagerverwaltung, muss er erst
#{link_to("neu angelegt", new_stock_article_path)} werden.
%hr/ %hr/
= f.input :delivered_on, as: :date_picker = f.input :delivered_on, as: :date_picker
= f.input :note, input_html: {size: '35x4'} = f.input :note, input_html: {size: '35x4'}
.form-actions .form-actions
= f.submit class: 'btn btn-primary' = f.submit class: 'btn btn-primary'
= link_to "oder abbrechen", supplier_deliveries_path(@supplier) = link_to t('ui.or_cancel'), supplier_deliveries_path(@supplier)
/ /
TODO: Fix this!! TODO: Fix this!!
.span6 .span6
%h2 Neuen Lagerartikel anlegen %h2= t '.new_article.title'
%p %p
Suche nach Artikeln aus dem = t('.new_article.search', supplier: @supplier.name).html_safe + ': '
%i= @supplier.name
Katalog:
= text_field_tag 'article_name' = text_field_tag 'article_name'
%hr/ %hr/
#stock_article_form #stock_article_form

View file

@ -3,4 +3,4 @@
= form.select :stock_article_id, stock_articles_for_select(supplier) = form.select :stock_article_id, stock_articles_for_select(supplier)
Menge Menge
= form.text_field :quantity, :size => 5, :autocomplete => 'off' = form.text_field :quantity, :size => 5, :autocomplete => 'off'
= link_to "Artikel aus Lieferung entfernen", "#", :class => 'remove_new_stock_change' = link_to t('.remove_article'), "#", :class => 'remove_new_stock_change'

Some files were not shown because too many files have changed in this diff Show more