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

23
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,15 +37,16 @@ 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'
gem 'binding_of_caller' gem 'binding_of_caller'
@ -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
@ -26,4 +31,4 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
(See file LICENSE for the full text of the GPL) (See file LICENSE for the full text of the GPL)

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
# delete articles
if params[:outlisted_articles]
params[:outlisted_articles].keys.each {|id| Article.find(id).destroy }
end end
end end
# Successfully done. end
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}" render :edit_all
redirect_to(supplier_articles_path(@supplier)) else
else # Successfully done.
flash.now.alert = e.message redirect_to supplier_articles_path(@supplier), notice: I18n.t('articles.controller.update_all.notice')
render :edit_all
end
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,
@ -30,4 +31,4 @@ class OrderByArticles < OrderPdf
end end
end end
end end

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
@ -48,4 +49,4 @@ class OrderByGroups < OrderPdf
end end
end end
end end

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,
@ -83,4 +84,4 @@ class OrderMatrix < OrderPdf
end end
end end
end end

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)
@ -21,7 +23,19 @@ class Group < ActiveRecord::Base
def user_tokens=(ids) def user_tokens=(ids)
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,25 +115,25 @@ 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
total += quantity * oa.price.price total += quantity * oa.price.price
when :gross when :gross
total += quantity * oa.price.gross_price total += quantity * oa.price.gross_price
when :fc when :fc
total += quantity * oa.price.fc_price total += quantity * oa.price.fc_price
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
when :groups_without_markup when :groups_without_markup
total += goa.result * goa.order_article.price.gross_price total += goa.result * goa.order_article.price.gross_price
end end
end end
end end
@ -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,20 +102,22 @@ 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
article_price.attributes = price_attributes if price_attributes.present?
if article_price.changed? article_price.attributes = price_attributes
# Updates also price attributes of article if update_current_price is selected if article_price.changed?
if update_current_price # Updates also price attributes of article if update_current_price is selected
article.update_attributes!(price_attributes) if update_current_price
self.article_price = article.article_prices.first # Assign new created article price to order article article.update_attributes!(price_attributes)
else self.article_price = article.article_prices.first # Assign new created article price to order article
# Creates a new article_price if neccessary else
# Set created_at timestamp to order ends, to make sure the current article price isn't changed # Creates a new article_price if neccessary
create_article_price!(price_attributes.merge(created_at: order.ends)) and save # Set created_at timestamp to order ends, to make sure the current article price isn't changed
end create_article_price!(price_attributes.merge(created_at: order.ends)) and save
end
# Updates ordergroup values # Updates ordergroup values
update_ordergroup_prices update_ordergroup_prices
end
end end
end end
end end
@ -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
@ -116,6 +115,16 @@ class Ordergroup < Group
errors.add :name, message errors.add :name, message
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

@ -7,6 +7,12 @@ 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|
@ -31,4 +32,4 @@
%td= form.text_field 'deposit', class: 'input-mini' %td= form.text_field 'deposit', class: 'input-mini'
- unless article.errors.empty? - unless article.errors.empty?
%tr.alert %tr.alert
%td(colspan="10")= article.errors.full_messages.join(", ") %td(colspan="10")= article.errors.full_messages.join(", ")

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,71 +1,70 @@
%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
%th Name
%th Notiz
%th Hersteller
%th Herkunft
%th Einheit
%th GebGr
%th Preis
%th MwSt.
%th Pfand
%th Kategorie
- @updated_articles.each do |@article, unequal_attributes|
- article = Article.find(@article.id)
%tr{:style => 'color:grey'}
%td= article.name
%td= article.note
%td= article.manufacturer
%td= article.origin
%td= article.unit
%td= article.unit_quantity
%td= article.price
%td= article.tax
%td= article.deposit
%td= article.article_category.name if article.article_category
%tr %tr
- fields_for 'articles[]', @article do |form| %th= t 'simple_form.labels.article.name'
%td{:style => highlight_new(unequal_attributes, :name)} %th= t 'simple_form.labels.article.note'
= form.text_field 'name', :size => 0 %th= t 'simple_form.labels.article.manufacturer'
= form.hidden_field 'shared_updated_on' %th= t 'simple_form.labels.article.origin'
%td{:style => highlight_new(unequal_attributes, :note)}= form.text_field 'note', :size => 15 %th= t 'simple_form.labels.article.unit'
%td{:style => highlight_new(unequal_attributes, :manufacturer)}= form.text_field 'manufacturer', :size => 10 %th= t '.unit_quantity_short'
%td{:style => highlight_new(unequal_attributes, :origin)}= form.text_field 'origin', :size => 5 %th= t '.price_short'
%td{:style => highlight_new(unequal_attributes, :unit)}= form.text_field 'unit', :size => 5 %th= t 'simple_form.labels.defaults.tax'
%td{:style => highlight_new(unequal_attributes, :unit_quantity)}= form.text_field 'unit_quantity', :size => 5 %th= t 'simple_form.labels.defaults.deposit'
%td{:style => highlight_new(unequal_attributes, :price)}= form.text_field 'price', :size => 5 %th= t 'simple_form.labels.article.article_category'
%td{:style => highlight_new(unequal_attributes, :tax)}= form.text_field 'tax', :size => 4 %tbody
%td{:style => highlight_new(unequal_attributes, :deposit)}= form.text_field 'deposit', :size => 4 - @updated_articles.each do |updated_article, attrs|
%td= select 'article[]', 'article_category_id', ArticleCategory.find(:all).collect {|a| [ a.name, a.id ] }, { :include_blank => true } - article = Article.find(updated_article.id)
%tr{:style => 'color:grey'}
%td= article.name
%td= article.note
%td= article.manufacturer
%td= article.origin
%td= article.unit
%td= article.unit_quantity
%td= article.price
%td= article.tax
%td= article.deposit
%td= article.article_category.name if article.article_category
%tr
= fields_for 'articles[]', updated_article do |form|
%td{:style => highlight_new(attrs, :name)}
= form.text_field 'name', :size => 0
= form.hidden_field 'shared_updated_on'
%td{:style => highlight_new(attrs, :note)}= form.text_field 'note', class: 'input-small'
%td{:style => highlight_new(attrs, :manufacturer)}= form.text_field 'manufacturer', class: 'input-small'
%td{:style => highlight_new(attrs, :origin)}= form.text_field 'origin', class: 'input-mini'
%td{:style => highlight_new(attrs, :unit)}= form.text_field 'unit', class: 'input-mini'
%td{:style => highlight_new(attrs, :unit_quantity)}= form.text_field 'unit_quantity', class: 'input-mini'
%td{:style => highlight_new(attrs, :price)}= form.text_field 'price', class: 'input-mini'
%td{:style => highlight_new(attrs, :tax)}= form.text_field 'tax', class: 'input-mini'
%td{:style => highlight_new(attrs, :deposit)}= form.text_field 'deposit', class: 'input-mini'
%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 %pre
wird beim Einlesen ignoriert. = [t('.fields.status'),
%br/ t('simple_form.labels.defaults.order_number'),
Die Felder müssen mit einem Semikolon (';') getrennt und der Text mit doppelten t('simple_form.labels.article.name'),
Anführungszeichen ("Text...") umklammert werden. t('simple_form.labels.article.note'),
%br/ t('simple_form.labels.article.manufacturer'),
Als Zeichensatz wird UTF-8 erwartet. Korrekte Reihenfolge der Spalten: t('simple_form.labels.article.origin'),
%pre t('simple_form.labels.article.unit'),
= ["Status (x=ausgelistet)", "Bestellnummer", "Name", "Notiz", "Hersteller", "Herkunft", t('simple_form.labels.defaults.price'),
"Einheit", "Preis(netto)", "MwSt", "Pfand", "Gebindegröße", t('simple_form.labels.defaults.tax'),
"Staffelmenge", "Staffelpreis", "Kategorie"].join(" | ") 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