Merge branch 'master' into allow-no-nickname

Conflicts:
	app/views/foodcoop/users/_users.html.haml
This commit is contained in:
wvengen 2013-10-29 19:15:52 +01:00
commit c37ed74942
84 changed files with 1712 additions and 2579 deletions

5
.gitignore vendored
View file

@ -1,6 +1,7 @@
log/*.log log/*.log
tmp/**/* tmp/**/*
config/*.yml config/app_config.yml
config/database.yml
config/initializers/secret_token.rb config/initializers/secret_token.rb
db/*.sqlite3 db/*.sqlite3
nbproject/ nbproject/
@ -16,4 +17,4 @@ doc/app/
Capfile Capfile
config/deploy.rb config/deploy.rb
config/deploy/* config/deploy/*
.localeapp .localeapp

14
Gemfile
View file

@ -9,24 +9,26 @@ gem "rails", '~> 3.2.9'
group :assets do group :assets do
gem 'sass-rails', '~> 3.2.3' gem 'sass-rails', '~> 3.2.3'
gem 'coffee-rails', '~> 3.2.1' gem 'coffee-rails', '~> 3.2.1'
gem 'less-rails'
gem 'uglifier', '>= 1.0.3'
# 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'
end end
gem 'jquery-rails' gem 'jquery-rails'
gem 'select2-rails' gem 'select2-rails'
gem 'bootstrap-datepicker-rails' gem 'bootstrap-datepicker-rails'
gem 'rails-assets-listjs', '0.2.0.beta.4' # remember to maintain list.*.js plugins and template engines on update
gem 'i18n-js', git: 'git://github.com/fnando/i18n-js.git' # to avoid US-ASCII js.erb error
gem 'rails-i18n'
gem 'mysql2' gem 'mysql2'
gem 'prawn' gem 'prawn'
gem 'haml-rails' gem 'haml-rails'
gem 'kaminari' gem 'kaminari'
gem 'client_side_validations'
gem 'simple_form' gem 'simple_form'
gem 'client_side_validations'
gem 'client_side_validations-simple_form'
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'
@ -42,7 +44,7 @@ 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'
end end
group :development do group :development do

View file

@ -4,6 +4,13 @@ GIT
specs: specs:
localize_input (0.1.0) localize_input (0.1.0)
GIT
remote: git://github.com/fnando/i18n-js.git
revision: eab4137f83777963f0ebe6960704a7f64fd8911d
specs:
i18n-js (2.1.2)
i18n
GIT GIT
remote: git://github.com/technoweenie/acts_as_versioned.git remote: git://github.com/technoweenie/acts_as_versioned.git
revision: 63b1fc8529d028fae632fe80ec0cb25df56cd76b revision: 63b1fc8529d028fae632fe80ec0cb25df56cd76b
@ -15,12 +22,12 @@ GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
Ascii85 (1.0.2) Ascii85 (1.0.2)
actionmailer (3.2.13) actionmailer (3.2.15)
actionpack (= 3.2.13) actionpack (= 3.2.15)
mail (~> 2.5.3) mail (~> 2.5.4)
actionpack (3.2.13) actionpack (3.2.15)
activemodel (= 3.2.13) activemodel (= 3.2.15)
activesupport (= 3.2.13) activesupport (= 3.2.15)
builder (~> 3.0.0) builder (~> 3.0.0)
erubis (~> 2.7.0) erubis (~> 2.7.0)
journey (~> 1.0.4) journey (~> 1.0.4)
@ -28,31 +35,33 @@ GEM
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.13) activemodel (3.2.15)
activesupport (= 3.2.13) activesupport (= 3.2.15)
builder (~> 3.0.0) builder (~> 3.0.0)
activerecord (3.2.13) activerecord (3.2.15)
activemodel (= 3.2.13) activemodel (= 3.2.15)
activesupport (= 3.2.13) activesupport (= 3.2.15)
arel (~> 3.0.2) arel (~> 3.0.2)
tzinfo (~> 0.3.29) tzinfo (~> 0.3.29)
activeresource (3.2.13) activeresource (3.2.15)
activemodel (= 3.2.13) activemodel (= 3.2.15)
activesupport (= 3.2.13) activesupport (= 3.2.15)
activesupport (3.2.13) activesupport (3.2.15)
i18n (= 0.6.1) i18n (~> 0.6, >= 0.6.4)
multi_json (~> 1.0) multi_json (~> 1.0)
acts_as_tree (1.2.0) acts_as_tree (1.4.0)
activerecord (>= 3.0.0) activerecord (>= 3.0.0)
afm (0.2.0)
arel (3.0.2) arel (3.0.2)
better_errors (0.2.0) better_errors (1.0.1)
coderay (>= 1.0.0) coderay (>= 1.0.0)
erubis (>= 2.7.0) erubis (>= 2.6.6)
binding_of_caller (0.6.8) binding_of_caller (0.7.2)
bootstrap-datepicker-rails (1.1.1.1) debug_inspector (>= 0.0.1)
bootstrap-datepicker-rails (1.1.1.8)
railties (>= 3.0) railties (>= 3.0)
builder (3.0.4) builder (3.0.4)
bullet (4.3.0) bullet (4.6.0)
uniform_notifier uniform_notifier
capistrano (2.13.5) capistrano (2.13.5)
highline highline
@ -70,72 +79,78 @@ GEM
xpath (~> 2.0) xpath (~> 2.0)
childprocess (0.3.9) childprocess (0.3.9)
ffi (~> 1.0, >= 1.0.11) ffi (~> 1.0, >= 1.0.11)
chronic (0.9.0) chronic (0.10.2)
client_side_validations (3.1.4) client_side_validations (3.2.6)
coderay (1.0.8) client_side_validations-simple_form (2.1.0)
client_side_validations (~> 3.2.5)
simple_form (~> 2.1.0)
coderay (1.1.0)
coffee-rails (3.2.2) coffee-rails (3.2.2)
coffee-script (>= 2.2.0) coffee-script (>= 2.2.0)
railties (~> 3.2.0) railties (~> 3.2.0)
coffee-script (2.2.0) coffee-script (2.2.0)
coffee-script-source coffee-script-source
execjs execjs
coffee-script-source (1.3.3) coffee-script-source (1.6.3)
commonjs (0.2.6) commonjs (0.2.7)
daemons (1.1.9) daemons (1.1.9)
database_cleaner (0.7.1) database_cleaner (1.2.0)
debug_inspector (0.0.2)
diff-lcs (1.2.4) diff-lcs (1.2.4)
erubis (2.7.0) erubis (2.7.0)
eventmachine (1.0.3) eventmachine (1.0.3)
exception_notification (2.6.1) exception_notification (4.0.1)
actionmailer (>= 3.0.4) actionmailer (>= 3.0.4)
execjs (1.4.0) activesupport (>= 3.0.4)
multi_json (~> 1.0) execjs (2.0.2)
expression_parser (0.9.0) expression_parser (0.9.0)
factory_girl (4.2.0) factory_girl (4.2.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
factory_girl_rails (4.2.1) factory_girl_rails (4.2.1)
factory_girl (~> 4.2.0) factory_girl (~> 4.2.0)
railties (>= 3.0.0) railties (>= 3.0.0)
faker (1.1.2) faker (1.2.0)
i18n (~> 0.5) i18n (~> 0.5)
ffi (1.9.0) ffi (1.9.0)
haml (3.1.7) haml (4.0.3)
haml-rails (0.3.5) tilt
haml-rails (0.4)
actionpack (>= 3.1, < 4.1) actionpack (>= 3.1, < 4.1)
activesupport (>= 3.1, < 4.1) activesupport (>= 3.1, < 4.1)
haml (~> 3.1) haml (>= 3.1, < 4.1)
railties (>= 3.1, < 4.1) railties (>= 3.1, < 4.1)
has_scope (0.5.1) has_scope (0.6.0.rc)
hashery (2.0.1) actionpack (>= 3.2, < 5)
highline (1.6.19) activesupport (>= 3.2, < 5)
hashery (2.1.1)
highline (1.6.20)
hike (1.2.3) hike (1.2.3)
i18n (0.6.1) i18n (0.6.5)
i18n-spec (0.4.0) i18n-spec (0.4.0)
iso iso
inherited_resources (1.3.1) inherited_resources (1.4.1)
has_scope (~> 0.5.0) has_scope (~> 0.6.0.rc)
responders (~> 0.6) responders (~> 1.0.0.rc)
iso (0.2.0) iso (0.2.0)
i18n i18n
journey (1.0.4) journey (1.0.4)
jquery-rails (2.1.3) jquery-rails (3.0.4)
railties (>= 3.1.0, < 5.0) railties (>= 3.0, < 5.0)
thor (~> 0.14) thor (>= 0.14, < 2.0)
json (1.7.7) json (1.8.1)
kaminari (0.14.1) kaminari (0.14.1)
actionpack (>= 3.0.0) actionpack (>= 3.0.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
less (2.2.2) less (2.4.0)
commonjs (~> 0.2.6) commonjs (~> 0.2.7)
less-rails (2.2.3) less-rails (2.4.2)
actionpack (>= 3.1) actionpack (>= 3.1)
less (~> 2.2.0) less (~> 2.4.0)
libv8 (3.3.10.4) libv8 (3.16.14.3)
mail (2.5.3) mail (2.5.4)
i18n (>= 0.4.0)
mime-types (~> 1.16) mime-types (~> 1.16)
treetop (~> 1.4.8) treetop (~> 1.4.8)
mailcatcher (0.5.11) mailcatcher (0.5.12)
activesupport (~> 3.0) activesupport (~> 3.0)
eventmachine (~> 1.0.0) eventmachine (~> 1.0.0)
haml (>= 3.1, < 5) haml (>= 3.1, < 5)
@ -149,24 +164,26 @@ GEM
activerecord (~> 3.1) activerecord (~> 3.1)
activesupport (~> 3.1) activesupport (~> 3.1)
polyamorous (~> 0.5.0) polyamorous (~> 0.5.0)
mime-types (1.21) mime-types (1.25)
mini_portile (0.5.1) mini_portile (0.5.2)
mono_logger (1.1.0) mono_logger (1.1.0)
multi_json (1.7.9) multi_json (1.8.2)
mysql2 (0.3.11) mysql2 (0.3.13)
net-scp (1.1.1) net-scp (1.1.2)
net-ssh (>= 2.6.5) net-ssh (>= 2.6.5)
net-sftp (2.1.2) net-sftp (2.1.2)
net-ssh (>= 2.6.5) net-ssh (>= 2.6.5)
net-ssh (2.6.7) net-ssh (2.7.0)
net-ssh-gateway (1.2.0) net-ssh-gateway (1.2.0)
net-ssh (>= 2.6.5) net-ssh (>= 2.6.5)
nokogiri (1.6.0) nokogiri (1.6.0)
mini_portile (~> 0.5.0) mini_portile (~> 0.5.0)
pdf-reader (1.2.0) pdf-reader (1.3.3)
Ascii85 (~> 1.0.0) Ascii85 (~> 1.0.0)
afm (~> 0.2.0)
hashery (~> 2.0) hashery (~> 2.0)
ruby-rc4 ruby-rc4
ttfunk
polyamorous (0.5.0) polyamorous (0.5.0)
activerecord (~> 3.0) activerecord (~> 3.0)
polyglot (0.3.3) polyglot (0.3.3)
@ -178,47 +195,53 @@ GEM
rack (1.4.5) rack (1.4.5)
rack-cache (1.2) rack-cache (1.2)
rack (>= 0.4) rack (>= 0.4)
rack-protection (1.5.0) rack-protection (1.5.1)
rack rack
rack-ssl (1.3.3) 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.13) rails (3.2.15)
actionmailer (= 3.2.13) actionmailer (= 3.2.15)
actionpack (= 3.2.13) actionpack (= 3.2.15)
activerecord (= 3.2.13) activerecord (= 3.2.15)
activeresource (= 3.2.13) activeresource (= 3.2.15)
activesupport (= 3.2.13) activesupport (= 3.2.15)
bundler (~> 1.0) bundler (~> 1.0)
railties (= 3.2.13) railties (= 3.2.15)
rails-assets-listjs (0.2.0.beta.4)
railties (>= 3.1)
rails-i18n (3.0.0)
i18n (~> 0.5)
rails (>= 3.0.0, < 4.0.0)
rails-settings-cached (0.2.4) rails-settings-cached (0.2.4)
rails (>= 3.0.0) rails (>= 3.0.0)
railties (3.2.13) railties (3.2.15)
actionpack (= 3.2.13) actionpack (= 3.2.15)
activesupport (= 3.2.13) activesupport (= 3.2.15)
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.1.0)
rdoc (3.12.2) rdoc (3.12.2)
json (~> 1.4) json (~> 1.4)
redis (3.0.4) redis (3.0.5)
redis-namespace (1.3.1) redis-namespace (1.3.1)
redis (~> 3.0.0) redis (~> 3.0.0)
responders (0.9.3) ref (1.0.5)
railties (~> 3.1) responders (1.0.0)
resque (1.24.1) railties (>= 3.2, < 5)
resque (1.25.1)
mono_logger (~> 1.0) mono_logger (~> 1.0)
multi_json (~> 1.0) multi_json (~> 1.0)
redis-namespace (~> 1.2) redis-namespace (~> 1.2)
sinatra (>= 0.9.2) sinatra (>= 0.9.2)
vegas (~> 0.1.2) vegas (~> 0.1.2)
rspec-core (2.14.2) rspec-core (2.14.6)
rspec-expectations (2.14.0) rspec-expectations (2.14.3)
diff-lcs (>= 1.1.3, < 2.0) diff-lcs (>= 1.1.3, < 2.0)
rspec-mocks (2.14.1) rspec-mocks (2.14.4)
rspec-rails (2.14.0) rspec-rails (2.14.0)
actionpack (>= 3.0) actionpack (>= 3.0)
activesupport (>= 3.0) activesupport (>= 3.0)
@ -229,22 +252,22 @@ GEM
ruby-prof (0.13.0) ruby-prof (0.13.0)
ruby-rc4 (0.1.5) ruby-rc4 (0.1.5)
rubyzip (0.9.9) rubyzip (0.9.9)
sass (3.2.1) sass (3.2.12)
sass-rails (3.2.5) sass-rails (3.2.6)
railties (~> 3.2.0) railties (~> 3.2.0)
sass (>= 3.1.10) sass (>= 3.1.10)
tilt (~> 1.3) tilt (~> 1.3)
select2-rails (3.4.2) select2-rails (3.5.0)
sass-rails
thor (~> 0.14) thor (~> 0.14)
selenium-webdriver (2.35.1) selenium-webdriver (2.35.1)
childprocess (>= 0.2.5) childprocess (>= 0.2.5)
multi_json (~> 1.0) multi_json (~> 1.0)
rubyzip (< 1.0.0) rubyzip (< 1.0.0)
websocket (~> 1.0.4) websocket (~> 1.0.4)
simple-navigation (3.9.0) simple-navigation (3.11.0)
activesupport (>= 2.3.2) activesupport (>= 2.3.2)
simple-navigation-bootstrap (0.0.4) simple-navigation-bootstrap (1.0.0)
railties (>= 3.1)
simple-navigation (>= 3.7.0) simple-navigation (>= 3.7.0)
simple_form (2.1.0) simple_form (2.1.0)
actionpack (~> 3.0) actionpack (~> 3.0)
@ -253,10 +276,10 @@ GEM
multi_json (~> 1.0) multi_json (~> 1.0)
simplecov-html (~> 0.7.1) simplecov-html (~> 0.7.1)
simplecov-html (0.7.1) simplecov-html (0.7.1)
sinatra (1.3.6) sinatra (1.4.4)
rack (~> 1.4) rack (~> 1.4)
rack-protection (~> 1.3) rack-protection (~> 1.4)
tilt (~> 1.3, >= 1.3.3) tilt (~> 1.3, >= 1.3.4)
skinny (0.2.3) skinny (0.2.3)
eventmachine (~> 1.0.0) eventmachine (~> 1.0.0)
thin (~> 1.5.0) thin (~> 1.5.0)
@ -265,33 +288,34 @@ GEM
multi_json (~> 1.0) multi_json (~> 1.0)
rack (~> 1.0) rack (~> 1.0)
tilt (~> 1.1, != 1.3.0) tilt (~> 1.1, != 1.3.0)
sqlite3 (1.3.6) sqlite3 (1.3.8)
therubyracer (0.10.2) therubyracer (0.12.0)
libv8 (~> 3.3.10) libv8 (~> 3.16.14.0)
ref
thin (1.5.1) thin (1.5.1)
daemons (>= 1.0.9) daemons (>= 1.0.9)
eventmachine (>= 0.12.6) eventmachine (>= 0.12.6)
rack (>= 1.0.0) rack (>= 1.0.0)
thor (0.17.0) thor (0.18.1)
tilt (1.4.1) tilt (1.4.1)
treetop (1.4.12) treetop (1.4.15)
polyglot polyglot
polyglot (>= 0.3.1) polyglot (>= 0.3.1)
ttfunk (1.0.3) ttfunk (1.0.3)
twitter-bootstrap-rails (2.1.3) twitter-bootstrap-rails (2.2.8)
actionpack (>= 3.1) actionpack (>= 3.1)
less-rails (~> 2.2.3) execjs
rails (>= 3.1)
railties (>= 3.1) railties (>= 3.1)
therubyracer (~> 0.10.2) tzinfo (0.3.38)
tzinfo (0.3.37) uglifier (2.2.1)
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)
uniform_notifier (1.1.1) uniform_notifier (1.3.0)
vegas (0.1.11) vegas (0.1.11)
rack (>= 1.0.0) rack (>= 1.0.0)
websocket (1.0.7) websocket (1.0.7)
whenever (0.8.1) whenever (0.8.4)
activesupport (>= 2.3.4) activesupport (>= 2.3.4)
chronic (>= 0.6.3) chronic (>= 0.6.3)
wikicloth (0.8.0) wikicloth (0.8.0)
@ -314,6 +338,7 @@ DEPENDENCIES
capistrano-ext capistrano-ext
capybara (~> 2.1.0) capybara (~> 2.1.0)
client_side_validations client_side_validations
client_side_validations-simple_form
coffee-rails (~> 3.2.1) coffee-rails (~> 3.2.1)
daemons daemons
database_cleaner database_cleaner
@ -321,10 +346,12 @@ DEPENDENCIES
factory_girl_rails (~> 4.0) factory_girl_rails (~> 4.0)
faker faker
haml-rails haml-rails
i18n-js!
i18n-spec i18n-spec
inherited_resources inherited_resources
jquery-rails jquery-rails
kaminari kaminari
less-rails
localize_input! localize_input!
mailcatcher mailcatcher
meta_search meta_search
@ -332,6 +359,8 @@ DEPENDENCIES
prawn prawn
quiet_assets quiet_assets
rails (~> 3.2.9) rails (~> 3.2.9)
rails-assets-listjs (= 0.2.0.beta.4)
rails-i18n
rails-settings-cached (= 0.2.4) rails-settings-cached (= 0.2.4)
resque resque
rspec-core rspec-core

View file

@ -3,16 +3,30 @@ FoodSoft
[![Build Status](https://travis-ci.org/foodcoops/foodsoft.png)](https://travis-ci.org/foodcoops/foodsoft) [![Build Status](https://travis-ci.org/foodcoops/foodsoft.png)](https://travis-ci.org/foodcoops/foodsoft)
[![Code Climate](https://codeclimate.com/github/foodcoops/foodsoft.png)](https://codeclimate.com/github/foodcoops/foodsoft) [![Code Climate](https://codeclimate.com/github/foodcoops/foodsoft.png)](https://codeclimate.com/github/foodcoops/foodsoft)
[![Dependency Status](https://gemnasium.com/foodcoops/foodsoft.png)](https://gemnasium.com/foodcoops/foodsoft) [![Dependency Status](https://gemnasium.com/foodcoops/foodsoft.png)](https://gemnasium.com/foodcoops/foodsoft)
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/foodcoops/foodsoft/trend.png)](https://bitdeli.com/free "Bitdeli Badge") [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/foodcoops/foodsoft/trend.png)](https://bitdeli.com/foodcoops "Bitdeli Badge")
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).
If you're a food coop considering to use foodsoft, please have a look at the [wiki page for foodcoops](https://github.com/foodcoops/foodsoft/wiki/For-foodcoops). When you'd like to experiment with or develop foodsoft, you can read [how to set it up](https://github.com/foodcoops/foodsoft/blob/master/doc/SETUP_DEVELOPMENT.md) on your own computer.
More information about using this software and contributing can be found on the [wiki](https://github.com/foodcoops/foodsoft/wiki). More information about using this software and contributing can be found on the [wiki](https://github.com/foodcoops/foodsoft/wiki).
Install
--------
Have a look at [DEVELOPMENT](https://github.com/foodcoops/foodsoft/blob/master/doc/DEVELOPMENT) (possibly outdated) and the (more recent) [Developing Guidelines](https://github.com/foodcoops/foodsoft/wiki/Developing-Guidelines) page on the wiki. Developing
----------
Get foodsoft [running locally](https://github.com/foodcoops/foodsoft/blob/master/doc/SETUP_DEVELOPMENT.md),
then visit our [Developing Guidelines](https://github.com/foodcoops/foodsoft/wiki/Developing-Guidelines)
page on the wiki.
Deploying
---------
Setup foodsoft to [run in production](https://github.com/foodcoops/foodsoft/blob/master/doc/SETUP_PRODUCTION.md),
and automate [deployment](https://github.com/foodcoops/foodsoft/blob/master/doc/DEPLOYMENT.md). This section is
very much a work in progress.
License License
------- -------

View file

@ -1,5 +1,4 @@
//= require jquery //= require jquery
//= require jquery-ui
//= require jquery_ujs //= require jquery_ujs
//= require select2 //= require select2
//= require twitter/bootstrap //= require twitter/bootstrap
@ -7,8 +6,16 @@
//= require bootstrap-datepicker/core //= require bootstrap-datepicker/core
//= require bootstrap-datepicker/locales/bootstrap-datepicker.de //= require bootstrap-datepicker/locales/bootstrap-datepicker.de
//= require bootstrap-datepicker/locales/bootstrap-datepicker.nl //= require bootstrap-datepicker/locales/bootstrap-datepicker.nl
//= require bootstrap-datepicker/locales/bootstrap-datepicker.fr
//= require jquery.observe_field //= require jquery.observe_field
//= require list
//= require list.unlist
//= require list.delay
//= require list.reset
//= require rails.validations //= require rails.validations
//= require rails.validations.simple_form
//= require i18n
//= require i18n/translations
//= require_self //= require_self
//= require ordering //= require ordering
//= require stupidtable //= require stupidtable
@ -30,19 +37,19 @@ $.fn.extend({
$(function() { $(function() {
// Show/Hide a specific DOM element // Show/Hide a specific DOM element
$('a[data-toggle-this]').live('click', function() { $(document).on('click', 'a[data-toggle-this]', function() {
$($(this).data('toggle-this')).toggle(); $($(this).data('toggle-this')).toggle();
return false; return false;
}); });
// Remove this item from DOM // Remove this item from DOM
$('a[data-remove-this]').live('click', function() { $(document).on('click', 'a[data-remove-this]', function() {
$($(this).data('remove-this')).remove(); $($(this).data('remove-this')).remove();
return false; return false;
}); });
// Check/Uncheck a single checkbox // Check/Uncheck a single checkbox
$('[data-check-this]').live('click', function() { $(document).on('click', '[data-check-this]', function() {
var checkbox = $($(this).data('check-this')); var checkbox = $($(this).data('check-this'));
checkbox.attr('checked', !checkbox.is(':checked')); checkbox.attr('checked', !checkbox.is(':checked'));
highlightRow(checkbox); highlightRow(checkbox);
@ -50,7 +57,7 @@ $(function() {
}); });
// Check/Uncheck all checkboxes for a specific form // Check/Uncheck all checkboxes for a specific form
$('input[data-check-all]').live('click', function() { $(document).on('click', 'input[data-check-all]', function() {
var status = $(this).is(':checked'); var status = $(this).is(':checked');
var context = $(this).data('check-all'); var context = $(this).data('check-all');
var elms = $('input[type="checkbox"]', context); var elms = $('input[type="checkbox"]', context);
@ -62,7 +69,7 @@ $(function() {
}); });
// Submit form when changing a select menu. // Submit form when changing a select menu.
$('form[data-submit-onchange] select').live('change', function() { $(document).on('change', 'form[data-submit-onchange] select', function() {
var confirmMessage = $(this).children(':selected').data('confirm'); var confirmMessage = $(this).children(':selected').data('confirm');
if (confirmMessage) { if (confirmMessage) {
if (confirm(confirmMessage)) { if (confirm(confirmMessage)) {
@ -95,7 +102,7 @@ $(function() {
}); });
// Remote paginations // Remote paginations
$('div.pagination[data-remote] a').live('click', function() { $(document).on('click', 'div.pagination[data-remote] a', function() {
$.getScript($(this).attr('href')); $.getScript($(this).attr('href'));
return false; return false;
}); });
@ -116,6 +123,20 @@ $(function() {
// Use bootstrap datepicker for dateinput // Use bootstrap datepicker for dateinput
$('.datepicker').datepicker({format: 'yyyy-mm-dd', language: I18n.locale}); $('.datepicker').datepicker({format: 'yyyy-mm-dd', language: I18n.locale});
// bootstrap tooltips (for price)
// Extra options don't work when using selector, so override defaults
// https://github.com/twbs/bootstrap/issues/3875 . These can still be
// overridden per tooltip using data-placement attributes and the like.
$.extend($.fn.tooltip.defaults, {
html: true,
animation: false,
placement: 'left',
container: 'body'
});
$(document).tooltip({
selector: '[data-toggle~="tooltip"]',
});
// See stupidtable.js for initialization of local table sorting // See stupidtable.js for initialization of local table sorting
}); });
@ -142,3 +163,5 @@ function highlightRow(checkbox) {
function setHiddenId(text, li) { function setHiddenId(text, li) {
$('hidden_id').value = li.id; $('hidden_id').value = li.id;
} }

View file

@ -1,4 +1,3 @@
jQuery -> jQuery ->
$("a[rel=popover]").popover() $("a[rel~=popover], .has-popover").popover()
$(".tooltip").tooltip() $("a[rel~=tooltip], .has-tooltip").tooltip()
$("a[rel=tooltip]").tooltip()

View file

@ -0,0 +1,50 @@
// for use with listjs 0.2.0
// https://github.com/javve/list.js
(function(window, undefined) {
window.List.prototype.plugins.delay = function(locals, options) {
var list = this;
this.searchTimeout = undefined;
var init = {
start: function(options) {
this.defaults(options);
this.callbacks(options);
this.onload(options);
},
defaults: function(options) {
options.delayedSearchClass = options.delayedSearchClass || 'delayed-search';
options.delayedSearchTime = options.delayedSearchTime || 500;
},
callbacks: function(options) {
$('.' + options.delayedSearchClass, list.listContainer).keyup(list.searchDelayStart);
},
onload: function(options) {
var initialSearchTerm = $('.' + options.delayedSearchClass, list.listContainer).val();
if('' != initialSearchTerm) {
list.search(initialSearchTerm);
}
}
};
this.searchDelayStart = function(searchString, columns) {
// TODO: if keycode corresponds to 'ENTER' ? skip delay
clearTimeout(list.searchTimeout);
list.searchTimeout = window.setTimeout(
function() {list.searchDelayEnd(searchString, columns)},
options.delayedSearchTime
);
$(list.listContainer).trigger('updateComing');
};
this.searchDelayEnd = function(searchString, columns) {
list.search(searchString, columns);
};
init.start(options);
}
})(window);

View file

@ -0,0 +1,42 @@
// for use with listjs 0.2.0
// https://github.com/javve/list.js
(function(window, undefined) {
window.List.prototype.plugins.reset = function(locals, options) {
var list = this;
var init = {
start: function(options) {
this.defaults(options);
this.callbacks(options);
},
defaults: function(options) {
options.highlightClass = options.highlightClass || 'btn-primary';
options.resetSearchClass = options.resetSearchClass || 'reset-search';
options.resettableClass = options.resettableClass || 'resettable';
},
callbacks: function(options) {
$('.' + options.resetSearchClass, list.listContainer).click(list.resetSearch);
list.on('updated', list.highlightResetButton);
$(list.listContainer).on('updateComing', function() {
list.highlightResetButton(false);
});
}
};
this.highlightResetButton = function(highlightEnabled) {
highlightEnabled = (undefined === highlightEnabled) ? (list.searched) : (highlightEnabled);
$('.' + options.resetSearchClass, list.listContainer).toggleClass(options.highlightClass, highlightEnabled);
};
this.resetSearch = function() {
$('.' + options.resettableClass, list.listContainer).val('');
list.search('');
};
init.start(options);
}
})(window);

View file

@ -0,0 +1,124 @@
// for use with listjs 0.2.0
// https://github.com/javve/list.js
/*******************************************************************************
********************************************************************************
The following code is a modification of list.js. It was created by copy-pasting
the original code with the copyright notice below.
********************************************************************************
*******************************************************************************/
/*******************************************************************************
Begin copyright notice of the original code
*******************************************************************************/
/*
ListJS Beta 0.2.0
By Jonny Strömberg (www.jonnystromberg.com, www.listjs.com)
OBS. The API is not frozen. It MAY change!
License (MIT)
Copyright (c) 2011 Jonny Strömberg http://jonnystromberg.com
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
/*******************************************************************************
End copyright notice of the original code
*******************************************************************************/
(function(w, undefined) {
/*******************************************************************************
Begin copy-pasted and modified code
*******************************************************************************/
// * template engine which adds class 'unlisted' instead of removing from DOM
// * especially useful in case of formulars
// * uses jQuery's $
w.List.prototype.templateEngines.unlist = function(list, settings) {
var h = w.ListJsHelpers;
// start with standard engine, override specific methods afterwards
this.superClass = w.List.prototype.templateEngines.standard;
this.superClass(list, settings);
// todo refer to listjs code instead of copy-pasting
var listSource = h.getByClass(settings.listClass, list.listContainer, true);
var templater = this;
var ensure = {
created: function(item) {
if(item.elm === undefined) {
templater.create(item);
}
}
};
var init = {
start: function(options) {
this.defaults(options);
this.callbacks(options);
},
defaults: function(options) {
options.listHeadingsClass = options.listHeadingsClass || 'list-heading';
},
callbacks: function(options) {
list.on('updated', templater.updateListHeadings);
}
};
this.show = function(item) {
ensure.created(item);
listSource.appendChild(item.elm); // append item (or move it to the end)
$(item.elm).removeClass('unlisted');
};
this.hide = function(item) {
ensure.created(item);
$(item.elm).addClass('unlisted');
listSource.appendChild(item.elm);
};
this.clear = function() {
$(listSource.childNodes).addClass('unlisted');
};
this.updateListHeadings = function() {
var headSel = '.' + settings.listHeadingsClass;
$(headSel, listSource).each(function() {
var listedCount = $(this).nextUntil(headSel, ':not(.unlisted)').length;
$(this).toggleClass('unlisted', 0==listedCount);
});
};
init.start(settings);
};
/*******************************************************************************
End copy-pasted and modified code
*******************************************************************************/
})(window);

View file

@ -7,9 +7,6 @@
var modified = false // indicates if anything has been clicked on this page var modified = false // indicates if anything has been clicked on this page
var groupBalance = 0; // available group money var groupBalance = 0; // available group money
var currencySeparator = "."; // default decimal separator
var currencyPrecision = 2; // default digits behind comma
var currencyUnit = "€"; // default currency
var minimumBalance = 0; // minimum group balance for the order to be succesful var minimumBalance = 0; // minimum group balance for the order to be succesful
var toleranceIsCostly = true; // default tolerance behaviour var toleranceIsCostly = true; // default tolerance behaviour
var isStockit = false; // Wheter the order is from stock oder normal supplier var isStockit = false; // Wheter the order is from stock oder normal supplier
@ -23,12 +20,6 @@ var toleranceOthers = new Array();
var itemsAllocated = new Array(); // how many items the group has been allocated and should definitely get var itemsAllocated = new Array(); // how many items the group has been allocated and should definitely get
var quantityAvailable = new Array(); // stock_order. how many items are currently in stock var quantityAvailable = new Array(); // stock_order. how many items are currently in stock
function setCurrencyFormat(separator, precision, unit) {
currencySeparator = separator;
currencyPrecision = precision;
currencyUnit = unit;
}
function setToleranceBehaviour(value) { function setToleranceBehaviour(value) {
toleranceIsCostly = value; toleranceIsCostly = value;
} }
@ -124,7 +115,7 @@ function update(item, quantity, tolerance) {
} else { } else {
itemTotal[item] = price[item] * (Number(quantity)); itemTotal[item] = price[item] * (Number(quantity));
} }
$('#price_' + item + '_display').html(asMoney(itemTotal[item])); $('#price_' + item + '_display').html(I18n.l("currency", itemTotal[item]));
// update missing units // update missing units
var missing_units = unit[item] - (((quantityOthers[item] + Number(quantity)) % unit[item]) + Number(tolerance) + toleranceOthers[item]) var missing_units = unit[item] - (((quantityOthers[item] + Number(quantity)) % unit[item]) + Number(tolerance) + toleranceOthers[item])
@ -137,10 +128,6 @@ function update(item, quantity, tolerance) {
updateBalance(); updateBalance();
} }
function asMoney(amount) {
return String(amount.toFixed(currencyPrecision)).replace(/\./, currencySeparator) + ' ' + currencyUnit;
}
function calcUnits(unitSize, quantity, tolerance) { function calcUnits(unitSize, quantity, tolerance) {
var units = Math.floor(quantity / unitSize) var units = Math.floor(quantity / unitSize)
var remainder = quantity % unitSize var remainder = quantity % unitSize
@ -158,10 +145,10 @@ function updateBalance() {
for (i in itemTotal) { for (i in itemTotal) {
total += itemTotal[i]; total += itemTotal[i];
} }
$('#total_price').html(asMoney(total)); $('#total_price').html(I18n.l("currency", total));
var balance = groupBalance - total; var balance = groupBalance - total;
$('#new_balance').html(asMoney(balance)); $('#new_balance').html(I18n.l("currency", balance));
$('#total_balance').val(asMoney(balance)); $('#total_balance').val(I18n.l("currency", balance));
// determine bgcolor and submit button state according to balance // determine bgcolor and submit button state according to balance
var bgcolor = ''; var bgcolor = '';
if (balance < minimumBalance) { if (balance < minimumBalance) {
@ -191,6 +178,6 @@ $(function() {
}); });
$('a[data-confirm_switch_order]').click(function() { $('a[data-confirm_switch_order]').click(function() {
return (!modified || confirm('Änderungen an dieser Bestellung gehen verloren, wenn zu einer anderen Bestellung gewechselt wird. Möchtest Du trotzdem wechseln?')); return (!modified || confirm(I18n.t('js.ordering.confirm_change')));
}); });
}); });

View file

@ -3,4 +3,5 @@
*= require select2 *= require select2
*= require token-input-bootstrappy *= require token-input-bootstrappy
*= require bootstrap-datepicker *= require bootstrap-datepicker
*= require list.unlist
*/ */

View file

@ -1,24 +1,23 @@
@import "twitter/bootstrap/bootstrap"; @import "twitter/bootstrap/bootstrap";
@import "twitter/bootstrap/responsive";
body { body {
padding-top: 10px; padding-top: 10px;
} }
@import "twitter/bootstrap/responsive";
// Set the correct sprite paths // Set the correct sprite paths
@iconSpritePath: asset-path('twitter/bootstrap/glyphicons-halflings.png'); @iconSpritePath: image-url('twitter/bootstrap/glyphicons-halflings.png');
@iconWhiteSpritePath: asset-path('twitter/bootstrap/glyphicons-halflings-white.png'); @iconWhiteSpritePath: image-url('twitter/bootstrap/glyphicons-halflings-white.png');
// Set the Font Awesome (Font Awesome is default. You can disable by commenting below lines) // Set the Font Awesome (Font Awesome is default. You can disable by commenting below lines)
// Note: If you use asset_path() here, your compiled boostrap_and_overrides.css will not @fontAwesomeEotPath: asset-url('fontawesome-webfont.eot');
// have the proper paths. So for now we use the absolute path. @fontAwesomeEotPath_iefix: asset-url('fontawesome-webfont.eot?#iefix');
@fontAwesomeEotPath: '/assets/fontawesome-webfont.eot'; @fontAwesomeWoffPath: asset-url('fontawesome-webfont.woff');
@fontAwesomeWoffPath: '/assets/fontawesome-webfont.woff'; @fontAwesomeTtfPath: asset-url('fontawesome-webfont.ttf');
@fontAwesomeTtfPath: '/assets/fontawesome-webfont.ttf'; @fontAwesomeSvgPath: asset-url('fontawesome-webfont.svg#fontawesomeregular');
@fontAwesomeSvgPath: '/assets/fontawesome-webfont.svg'; @import 'fontawesome/font-awesome';
// Font Awesome // Glyphicons
@import "fontawesome"; //@import "twitter/bootstrap/sprites.less";
// Your custom LESS stylesheets goes here // Your custom LESS stylesheets goes here
// //
@ -26,7 +25,7 @@ body {
// you may use and inherit here // you may use and inherit here
// //
// If you'd like to override bootstrap's own variables, you can do so here as well // If you'd like to override bootstrap's own variables, you can do so here as well
// See http://twitter.github.com/bootstrap/less.html for their names and documentation // See http://twitter.github.com/bootstrap/customize.html#variables for their names and documentation
// //
// Example: // Example:
// @linkColor: #ff0000; // @linkColor: #ff0000;
@ -238,3 +237,8 @@ tr.unavailable {
margin-bottom: 15px margin-bottom: 15px
} }
} }
// allow buttons as input add-on (with proper height)
.input-append button.add-on {
height: inherit;
}

View file

@ -0,0 +1,3 @@
.list .unlisted:not(.no-unlist) {
display: none;
}

View file

@ -26,7 +26,7 @@ class ApplicationController < ActionController::Base
def deny_access def deny_access
session[:return_to] = request.original_url session[:return_to] = request.original_url
redirect_to login_url, :alert => 'Access denied!' redirect_to login_url, :alert => I18n.t('application.controller.error_denied')
end end
private private
@ -37,7 +37,7 @@ class ApplicationController < ActionController::Base
# No user at all: redirect to login page. # No user at all: redirect to login page.
session[:user_id] = nil session[:user_id] = nil
session[:return_to] = request.original_url session[:return_to] = request.original_url
redirect_to login_url, :alert => 'Authentication required!' redirect_to login_url, :alert => I18n.t('application.controller.error_authn')
else else
# We have an authenticated user, now check role... # We have an authenticated user, now check role...
# Roles gets the user through his memberships. # Roles gets the user through his memberships.
@ -83,7 +83,7 @@ class ApplicationController < ActionController::Base
def authenticate_membership_or_admin def authenticate_membership_or_admin
@group = Group.find(params[:id]) @group = Group.find(params[:id])
unless @group.member?(@current_user) or @current_user.role_admin? unless @group.member?(@current_user) or @current_user.role_admin?
redirect_to root_path, alert: "Diese Aktion ist nur für Mitglieder der Gruppe erlaubt!" redirect_to root_path, alert: I18n.t('application.controller.error_members_only')
end end
end end

View file

@ -7,12 +7,12 @@ class ArticlesController < ApplicationController
sort = case params['sort'] sort = case params['sort']
when "name" then "articles.name" when "name" then "articles.name"
when "unit" then "articles.unit" when "unit" then "articles.unit"
when "category" then "article_categories.name" when "article_category" then "article_categories.name"
when "note" then "articles.note" when "note" then "articles.note"
when "availability" then "articles.availability" when "availability" then "articles.availability"
when "name_reverse" then "articles.name DESC" when "name_reverse" then "articles.name DESC"
when "unit_reverse" then "articles.unit DESC" when "unit_reverse" then "articles.unit DESC"
when "category_reverse" then "article_categories.name DESC" when "article_category_reverse" then "article_categories.name DESC"
when "note_reverse" then "articles.note DESC" when "note_reverse" then "articles.note DESC"
when "availability_reverse" then "articles.availability DESC" when "availability_reverse" then "articles.availability DESC"
end end

View file

@ -10,7 +10,7 @@ class Finance::BalancingController < Finance::BaseController
flash.now.alert = t('finance.balancing.new.alert') 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(:article, :article_price, @articles = @order.order_articles.ordered_or_member.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'

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: t('finance.financial_transactions.create.notice') redirect_to finance_ordergroup_transactions_url(@ordergroup), notice: I18n.t('finance.financial_transactions.controller.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
@ -44,16 +44,16 @@ class Finance::FinancialTransactionsController < ApplicationController
end end
def create_collection def create_collection
raise "Notiz wird benötigt!" if params[:note].blank? raise I18n.t('finance.financial_transactions.controller.create_collection.error_note_required') if params[:note].blank?
params[:financial_transactions].each do |trans| params[:financial_transactions].each do |trans|
# ignore empty amount fields ... # ignore empty amount fields ...
unless trans[:amount].blank? unless trans[:amount].blank?
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: t('finance.create_collection.create.notice') redirect_to finance_ordergroups_url, notice: I18n.t('finance.financial_transactions.controller.create_collection.notice')
rescue => error rescue => error
redirect_to finance_new_transaction_collection_url, alert: t('finance.create_collection.create.alert', error: error.to_s) redirect_to finance_new_transaction_collection_url, alert: I18n.t('finance.financial_transactions.controller.create_collection.alert', error: error.to_s)
end end
protected protected

View file

@ -11,7 +11,7 @@ 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. 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 redirect_to forgot_password_url, alert: I18n.t('errors.general_again') and return
end end
if (user = User.find_by_email(params[:user][:email])) if (user = User.find_by_email(params[:user][:email]))

View file

@ -98,6 +98,8 @@ class OrdersController < ApplicationController
order = Order.find(params[:id]) order = Order.find(params[:id])
order.finish!(@current_user) order.finish!(@current_user)
redirect_to order, notice: I18n.t('orders.finish.notice') redirect_to order, notice: I18n.t('orders.finish.notice')
rescue => error
redirect_to orders_url, alert: I18n.t('errors.general_msg', :msg => error.message)
end end
# Renders the fax-text-file # Renders the fax-text-file
@ -107,9 +109,9 @@ class OrdersController < ApplicationController
supplier = order.supplier supplier = order.supplier
contact = FoodsoftConfig[:contact].symbolize_keys contact = FoodsoftConfig[:contact].symbolize_keys
text = I18n.t('orders.fax.heading', :name => FoodsoftConfig[:name]) text = I18n.t('orders.fax.heading', :name => FoodsoftConfig[:name])
text += "\n" + I18n.t('orders.fax.customer_number') + ': #{supplier.customer_number}' unless supplier.customer_number.blank? text += "\n#{Supplier.human_attribute_name(:customer_number)}: #{supplier.customer_number}" unless supplier.customer_number.blank?
text += "\n" + I18n.t('orders.fax.delivery_day') text += "\n" + I18n.t('orders.fax.delivery_day')
text += "\n\n#{supplier.name}\n#{supplier.address}\n" + I18n.t('simple_form.labels.supplier.fax') + ": #{supplier.fax}\n\n" text += "\n\n#{supplier.name}\n#{supplier.address}\n#{Supplier.human_attribute_name(:fax)}: #{supplier.fax}\n\n"
text += "****** " + I18n.t('orders.fax.to_address') + "\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 += "****** " + I18n.t('orders.fax.articles') + "\n\n" text += "****** " + I18n.t('orders.fax.articles') + "\n\n"

View file

@ -31,6 +31,11 @@ class StockitController < ApplicationController
end end
end end
def show
@stock_article = StockArticle.find(params[:id])
@stock_changes = @stock_article.stock_changes.order('stock_changes.created_at DESC')
end
def destroy def destroy
@article = StockArticle.find(params[:id]) @article = StockArticle.find(params[:id])
@article.mark_as_deleted @article.mark_as_deleted
@ -55,9 +60,4 @@ class StockitController < ApplicationController
render :partial => 'form', :locals => {:stock_article => stock_article} render :partial => 'form', :locals => {:stock_article => stock_article}
end end
def history
@stock_article = StockArticle.undeleted.find(params[:stock_article_id])
@stock_changes = @stock_article.stock_changes.order('stock_changes.created_at DESC').each {|s| s.readonly!}
end
end end

View file

@ -21,15 +21,15 @@ class OrderFax < OrderPdf
text "#{contact[:zip_code]} #{contact[:city]}", size: 9, align: :right text "#{contact[:zip_code]} #{contact[:city]}", size: 9, align: :right
move_down 5 move_down 5
unless @order.supplier.try(:customer_number).blank? unless @order.supplier.try(:customer_number).blank?
text "#{I18n.t('simple_form.labels.supplier.customer_number')}: #{@order.supplier[:customer_number]}", size: 9, align: :right text "#{Supplier.human_attribute_name :customer_number}: #{@order.supplier[:customer_number]}", size: 9, align: :right
move_down 5 move_down 5
end end
unless contact[:phone].blank? unless contact[:phone].blank?
text "#{I18n.t('simple_form.labels.supplier.phone')}: #{contact[:phone]}", size: 9, align: :right text "#{Supplier.human_attribute_name :phone}: #{contact[:phone]}", size: 9, align: :right
move_down 5 move_down 5
end end
unless contact[:email].blank? unless contact[:email].blank?
text "#{I18n.t('simple_form.labels.supplier.email')}: #{contact[:email]}", size: 9, align: :right text "#{Supplier.human_attribute_name :email}: #{contact[:email]}", size: 9, align: :right
end end
end end
@ -40,7 +40,7 @@ class OrderFax < OrderPdf
text @order.supplier.try(:address).to_s text @order.supplier.try(:address).to_s
unless @order.supplier.try(:fax).blank? unless @order.supplier.try(:fax).blank?
move_down 5 move_down 5
text "#{I18n.t('simple_form.labels.supplier.fax')}: #{@order.supplier[:fax]}" text "#{Supplier.human_attribute_name :fax}: #{@order.supplier[:fax]}"
end end
end end
@ -48,10 +48,10 @@ class OrderFax < OrderPdf
text Date.today.strftime(I18n.t('date.formats.default')), align: :right text Date.today.strftime(I18n.t('date.formats.default')), align: :right
move_down 10 move_down 10
text "#{I18n.t('simple_form.labels.delivery.delivered_on')}:" text "#{Delivery.human_attribute_name :delivered_on}:"
move_down 10 move_down 10
unless @order.supplier.try(:contact_person).blank? unless @order.supplier.try(:contact_person).blank?
text "#{I18n.t('simple_form.labels.supplier.contact_person')}: #{@order.supplier[:contact_person]}" text "#{Supplier.human_attribute_name :contact_person}: #{@order.supplier[:contact_person]}"
move_down 10 move_down 10
end end

View file

@ -73,6 +73,22 @@ module ApplicationHelper
link_to(text, url_for(url_options), html_options) link_to(text, url_for(url_options), html_options)
end end
# Generates text for table heading for model attribute
# When the 'short' option is true, abbreviations will be used:
# When there is a non-empty model attribute 'foo', it looks for
# the model attribute translation 'foo_short' and use that as
# heading, with an acronym title of 'foo'.
# Other options are passed through to I18n.
def heading_helper(model, attribute, options = {})
i18nopts = options.select {|a| !['short'].include?(a) }
s = model.human_attribute_name(attribute, i18nopts)
if options[:short]
sshort = model.human_attribute_name("#{attribute}_short".to_sym, options.merge({defaults: ''}))
s = raw "<acronym title='#{s}'>#{sshort}</acronym>" unless sshort.empty?
end
s
end
# Generates a link to the top of the website # Generates a link to the top of the website
def link_to_top def link_to_top

View file

@ -155,7 +155,7 @@ class Order < ActiveRecord::Base
unless finished? unless finished?
Order.transaction do Order.transaction do
# set new order state (needed by notify_order_finished) # set new order state (needed by notify_order_finished)
update_attributes(:state => 'finished', :ends => Time.now, :updated_by => user) update_attributes!(:state => 'finished', :ends => Time.now, :updated_by => user)
# Update order_articles. Save the current article_price to keep price consistency # Update order_articles. Save the current article_price to keep price consistency
# Also save results for each group_order_result # Also save results for each group_order_result

View file

@ -12,7 +12,8 @@ class OrderArticle < ActiveRecord::Base
validate :article_and_price_exist validate :article_and_price_exist
validates_uniqueness_of :article_id, scope: :order_id validates_uniqueness_of :article_id, scope: :order_id
scope :ordered, :conditions => "units_to_order >= 1" scope :ordered, :conditions => "units_to_order > 0"
scope :ordered_or_member, -> { includes(:group_order_articles).where("units_to_order > 0 OR group_order_articles.result > 0") }
before_create :init_from_balancing before_create :init_from_balancing
after_destroy :update_ordergroup_prices after_destroy :update_ordergroup_prices

View file

@ -66,7 +66,7 @@ class Ordergroup < Group
end end
def avg_jobs_per_euro def avg_jobs_per_euro
stats[:orders_sum] != 0 ? stats[:jobs_size].to_f / stats[:orders_sum].to_f : 0 stats[:jobs_size].to_f / stats[:orders_sum].to_f rescue 0
end end
# This is the ordergroup job per euro performance # This is the ordergroup job per euro performance
@ -90,7 +90,7 @@ class Ordergroup < Group
# Global average # Global average
def self.avg_jobs_per_euro def self.avg_jobs_per_euro
stats = Ordergroup.pluck(:stats) stats = Ordergroup.pluck(:stats)
stats.sum {|s| s[:jobs_size].to_f } / stats.sum {|s| s[:orders_sum].to_f } stats.sum {|s| s[:jobs_size].to_f } / stats.sum {|s| s[:orders_sum].to_f } rescue 0
end end
def account_updated def account_updated

View file

@ -5,8 +5,8 @@
%table.table.table-striped %table.table.table-striped
%thead %thead
%tr %tr
%th= t('simple_form.labels.article_category.name') %th= heading_helper ArticleCategory, :name
%th= t('simple_form.labels.article_category.description') %th= heading_helper ArticleCategory, :description
%th %th
%tbody %tbody
- @article_categories.each do |article_category| - @article_categories.each do |article_category|

View file

@ -6,16 +6,15 @@
%thead %thead
%tr %tr
%th %th
%th= sort_link_helper t('simple_form.labels.article.name'), "name" %th= sort_link_helper heading_helper(Article, :name), "name"
%th %th
%th= sort_link_helper t('simple_form.labels.article.article_category'), "category" %th= sort_link_helper heading_helper(Article, :article_category), "article_category"
%th= sort_link_helper t('simple_form.labels.article.unit'), "unit" %th= sort_link_helper heading_helper(Article, :unit), "unit"
%th= sort_link_helper t('simple_form.labels.article.note'), "note" %th= sort_link_helper heading_helper(Article, :note), "note"
%th{:style => "width: 4em;"} %th{:style => "width: 4em;"}= heading_helper Article, :unit_quantity, short: true
%acronym{:title => t('.unit_quantity_desc')}= t '.unit_quantity_short' %th{:style => "width: 5em;"}= heading_helper Article, :price
%th{:style => "width: 5em;"}= t '.price_netto' %th{:style => "width: 3.5em;"}= heading_helper Article, :tax
%th{:style => "width: 3.5em;"}= t 'simple_form.labels.defaults.tax' %th{:style => "width: 4em;"}= heading_helper Article, :deposit
%th{:style => "width: 4em;"}= t 'simple_form.labels.defaults.deposit'
%th{:style => "width: 3em;"} %th{:style => "width: 3em;"}
%tbody#listbody %tbody#listbody

View file

@ -1,20 +1,16 @@
%table.table %table.table
%thead %thead
%tr %tr
%th %th= heading_helper Article, :availability, short: true
%acronym{:title => t('.available_desc')}= t '.available_short' %th= heading_helper Article, :name
%th= t 'simple_form.labels.article.name' %th= heading_helper Article, :unit
%th= t 'simple_form.labels.article.unit' %th= heading_helper Article, :price, short: true
%th %th= heading_helper Article, :unit_quantity, short: true
%acronym{:title => t('.price_desc')}= t '.price_short' %th= heading_helper Article, :order_number, short: true
%th %th= heading_helper Article, :note
%acronym{:title => t('.unit_quantity_desc')}= t '.unit_quantity_short' %th= heading_helper Article, :article_category
%th %th= heading_helper Article, :tax
%acronym{:title => t('.order_number_desc')}= t '.order_number_short' %th= heading_helper Article, :deposit
%th= t 'simple_form.labels.article.note'
%th= t 'simple_form.labels.article.article_category'
%th= t 'simple_form.labels.defaults.tax'
%th= t 'simple_form.labels.defaults.deposit'
%tbody %tbody
- @articles.each_with_index do |article, index| - @articles.each_with_index do |article, index|
= fields_for "articles[#{article.id || index}]", article do |form| = fields_for "articles[#{article.id || index}]", article do |form|

View file

@ -5,13 +5,13 @@
%table.table.table-striped %table.table.table-striped
%thead %thead
%tr %tr
%th= t 'simple_form.labels.article.name' %th= heading_helper Article, :name
%th= t 'simple_form.labels.article.origin' %th= heading_helper Article, :origin
%th= t 'simple_form.labels.article.manufacturer' %th= heading_helper Article, :manufacturer
%th= t 'simple_form.labels.article.note' %th= heading_helper Article, :note
%th{:style => "width:4em"}= t 'simple_form.labels.defaults.price' %th{:style => "width:4em"}= heading_helper Article, :price
%th= t 'simple_form.labels.article.unit' %th= heading_helper Article, :unit
%th= t 'simple_form.labels.defaults.unit_quantity' %th= heading_helper Article, :unit_quantity, short: true
%th %th
%tbody %tbody
- for article in @articles - for article in @articles

View file

@ -1,4 +1,4 @@
- title 'Artikel mit externer Datenbank synchronisieren' - title t('.title')
= form_tag update_synchronized_supplier_articles_path(@supplier) do = form_tag update_synchronized_supplier_articles_path(@supplier) do
%h2= t '.outlist.title' %h2= t '.outlist.title'
@ -11,30 +11,28 @@
= 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 - if article.in_open_order
.alert .alert= t '.alert_used', article: article.name
Achtung, #{article.name} wird gerade in einer laufenden Bestellung verwendet. Bitte erst Bestellung anpassen.
- else - else
%i= t '.outlist.body_skip' %i= t '.outlist.body_skip'
%hr/ %hr/
%h2= t '.update.title' %h2= t '.update.title'
%p %p
%i %i
%b= @updated_articles.size = t '.update.update_msg', count: @updated_articles.size
= t '.update.update_msg' = t '.update.body'
= t('.update.body').html_safe
%table.table %table.table
%thead %thead
%tr %tr
%th= t 'simple_form.labels.article.name' %th= heading_helper Article, :name
%th= t 'simple_form.labels.article.note' %th= heading_helper Article, :note
%th= t 'simple_form.labels.article.manufacturer' %th= heading_helper Article, :manufacturer
%th= t 'simple_form.labels.article.origin' %th= heading_helper Article, :origin
%th= t 'simple_form.labels.article.unit' %th= heading_helper Article, :unit
%th= t '.unit_quantity_short' %th= heading_helper Article, :unit_quantity, short: true
%th= t '.price_short' %th= heading_helper Article, :price
%th= t 'simple_form.labels.defaults.tax' %th= heading_helper Article, :tax
%th= t 'simple_form.labels.defaults.deposit' %th= heading_helper Article, :deposit
%th= t 'simple_form.labels.article.article_category' %th= heading_helper Article, :article_category
%tbody %tbody
- @updated_articles.each do |updated_article, attrs| - @updated_articles.each do |updated_article, attrs|
- article = Article.find(updated_article.id) - article = Article.find(updated_article.id)

View file

@ -2,19 +2,19 @@
= t('.body').html_safe = t('.body').html_safe
%pre %pre
= [t('.fields.status'), = [t('.fields.status'),
t('simple_form.labels.defaults.order_number'), Article.human_attribute_name(:order_number),
t('simple_form.labels.article.name'), Article.human_attribute_name(:name),
t('simple_form.labels.article.note'), Article.human_attribute_name(:note),
t('simple_form.labels.article.manufacturer'), Article.human_attribute_name(:manufacturer),
t('simple_form.labels.article.origin'), Article.human_attribute_name(:origin),
t('simple_form.labels.article.unit'), Article.human_attribute_name(:unit),
t('simple_form.labels.defaults.price'), Article.human_attribute_name(:price),
t('simple_form.labels.defaults.tax'), Article.human_attribute_name(:tax),
t('simple_form.labels.defaults.deposit'), Article.human_attribute_name(:deposit),
t('simple_form.labels.defaults.unit_quantity'), Article.human_attribute_name(:unit_quantity),
t('.fields.season_amount'), t('.fields.season_amount'),
t('.fields.season_price'), t('.fields.season_price'),
t('simple_form.labels.article.article_category')].join(" | ") Article.human_attribute_name(: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|

View file

@ -61,8 +61,6 @@
return true; return true;
} }
}); });
enablePriceTooltips();
}); });
function mark_article_for_delivery(stock_article_id) { function mark_article_for_delivery(stock_article_id) {
@ -80,14 +78,6 @@
return ( 0 == $('#stock_change_stock_article_' + stock_article_id).length ); return ( 0 == $('#stock_change_stock_article_' + stock_article_id).length );
} }
function enablePriceTooltips(context) {
$('[data-toggle~="tooltip"]', context).tooltip({
animation: false,
html: true,
placement: 'left'
});
}
= simple_form_for [@supplier, @delivery], validate: true do |f| = simple_form_for [@supplier, @delivery], validate: true do |f|
= f.error_notification = f.error_notification
= base_errors f.object = base_errors f.object

View file

@ -5,21 +5,18 @@
$('#stock_changes tr').removeClass('success'); $('#stock_changes tr').removeClass('success');
var quantity = w.prompt('<%= j(t('.how_many_units', :unit => @stock_change.stock_article.unit, :name => @stock_change.stock_article.name)) %>');
if(null === quantity) {
return false;
}
var stock_change = $( var stock_change = $(
'<%= j(render(:partial => 'stock_change', :locals => {:stock_change => @stock_change})) %>' '<%= j(render(:partial => 'stock_change', :locals => {:stock_change => @stock_change})) %>'
).addClass('success'); ).addClass('success');
enablePriceTooltips(stock_change); $('input.stock-change-quantity', stock_change).val(quantity);
$('#stock_changes').append(stock_change); $('#stock_changes').append(stock_change);
mark_article_for_delivery(<%= @stock_change.stock_article.id %>); mark_article_for_delivery(<%= @stock_change.stock_article.id %>);
updateSort('#stock_changes'); updateSort('#stock_changes');
var quantity = w.prompt('<%= j(t('.how_many_units', :unit => @stock_change.stock_article.unit, :name => @stock_change.stock_article.name)) %>'); <%# how to properly escape here? %>
if(null === quantity) {
stock_change.remove();
mark_article_for_delivery(<%= @stock_change.stock_article.id %>);
return false;
}
$('input.stock-change-quantity', stock_change).val(quantity);
})(window); })(window);

View file

@ -8,7 +8,6 @@ $('div.container-fluid').prepend(
var stock_article_for_adding = $( var stock_article_for_adding = $(
'<%= j(render(:partial => 'stock_article_for_adding', :locals => {:article => @stock_article})) %>' '<%= j(render(:partial => 'stock_article_for_adding', :locals => {:article => @stock_article})) %>'
).addClass('success'); ).addClass('success');
enablePriceTooltips(stock_article_for_adding);
$('#stock_articles_for_adding tbody').append(stock_article_for_adding); $('#stock_articles_for_adding tbody').append(stock_article_for_adding);
updateSort('#stock_articles_for_adding'); updateSort('#stock_articles_for_adding');

View file

@ -3,9 +3,9 @@
%table.table.table-striped %table.table.table-striped
%thead %thead
%tr %tr
%th= t 'simple_form.labels.delivery.delivered_on' %th= heading_helper Delivery, :delivered_on
%th.numeric= t 'deliveries.invoice_amount' %th.numeric= t 'deliveries.invoice_amount'
%th= t 'simple_form.labels.defaults.note' %th= heading_helper Delivery, :note
%tbody %tbody
- for delivery in @deliveries - for delivery in @deliveries
%tr %tr

View file

@ -1,16 +1,16 @@
- title t('.title') - title t('.title')
%dl %dl
%dt= t 'simple_form.labels.delivery.supplier' %dt= heading_helper Delivery, :supplier
%dd= @delivery.supplier.name %dd= @delivery.supplier.name
%dt= t 'simple_form.labels.delivery.delivered_on' %dt= heading_helper Delivery, :delivered_on
%dd= @delivery.delivered_on %dd= @delivery.delivered_on
%dt= t 'deliveries.invoice_amount' %dt= t 'deliveries.invoice_amount'
%dd= link_to_invoice(@delivery) %dd= link_to_invoice(@delivery)
- if @delivery.invoice - if @delivery.invoice
%dt= t 'deliveries.invoice_net_amount' %dt= t 'deliveries.invoice_net_amount'
%dd= number_to_currency @delivery.invoice.net_amount %dd= number_to_currency @delivery.invoice.net_amount
%dt= t 'simple_form.labels.defaults.note' %dt= heading_helper Delivery, :note
%dd= simple_format @delivery.note %dd= simple_format @delivery.note
%h2= t '.title_articles' %h2= t '.title_articles'

View file

@ -10,7 +10,6 @@ $('div.container-fluid').prepend(
var stock_article_for_adding = $( var stock_article_for_adding = $(
'<%= j(render(:partial => 'stock_article_for_adding', :locals => {:article => @stock_article, :delivery => @delivery})) %>' '<%= j(render(:partial => 'stock_article_for_adding', :locals => {:article => @stock_article, :delivery => @delivery})) %>'
).addClass('success'); ).addClass('success');
enablePriceTooltips(stock_article_for_adding);
$('#stock_article_<%= @stock_article.id %>').replaceWith(stock_article_for_adding); $('#stock_article_<%= @stock_article.id %>').replaceWith(stock_article_for_adding);
updateSort('#stock_articles_for_adding'); updateSort('#stock_articles_for_adding');

View file

@ -5,12 +5,12 @@
var ordergroup = "#{escape_javascript(render('ordergroup'))}" var ordergroup = "#{escape_javascript(render('ordergroup'))}"
$(function() { $(function() {
$('a[data-remove-transaction]').live('click', function() { $(document).on('click', 'a[data-remove-transaction]', function() {
$(this).parents('tr').remove(); $(this).parents('tr').remove();
return false; return false;
}); });
$('a[data-add-transaction]').click(function() { $(document).on('click', 'a[data-add-transaction]', function() {
$('#ordergroups').append(ordergroup); $('#ordergroups').append(ordergroup);
return false; return false;
}); });

View file

@ -5,7 +5,7 @@
%h3= t('.amount_change_for', article: @order_article.article.name) %h3= t('.amount_change_for', article: @order_article.article.name)
.modal-body .modal-body
= form.input :ordergroup_id, as: :select, collection: Ordergroup.all.map { |g| [g.name, g.id] } = form.input :ordergroup_id, as: :select, collection: Ordergroup.all.map { |g| [g.name, g.id] }
= form.input :result, hint: "Einheit: #{@order_article.article.unit}" = form.input :result, hint: I18n.t('.result_hint', unit: @order_article.article.unit)
.modal-footer .modal-footer
= link_to t('ui.close'), '#', class: 'btn', data: {dismiss: 'modal'} = link_to t('ui.close'), '#', class: 'btn', data: {dismiss: 'modal'}
= form.submit t('ui.save'), class: 'btn btn-primary' = form.submit t('ui.save'), class: 'btn btn-primary'

View file

@ -5,14 +5,14 @@
%table.table.table-striped %table.table.table-striped
%thead %thead
%tr %tr
%th= t 'simple_form.labels.invoice.number' %th= heading_helper Invoice, :number
%th= t 'simple_form.labels.invoice.supplier' %th= heading_helper Invoice, :supplier
%th= t 'simple_form.labels.invoice.date' %th= heading_helper Invoice, :date
%th= t 'simple_form.labels.invoice.paid_on' %th= heading_helper Invoice, :paid_on
%th= t 'simple_form.labels.invoice.amount' %th= heading_helper Invoice, :amount
%th= t 'simple_form.labels.invoice.delivery' %th= heading_helper Invoice, :delivery
%th= t 'simple_form.labels.invoice.order' %th= heading_helper Invoice, :order
%th= t 'simple_form.labels.invoice.note' %th= heading_helper Invoice, :note
%th %th
%th %th
%tbody %tbody

View file

@ -1,38 +1,38 @@
- title t('.title', number: @invoice.number) - title t('.title', number: @invoice.number)
%p %p
%b= t('simple_form.labels.invoice.supplier') + ':' %b= heading_helper(Invoice, :supplier) + ':'
= @invoice.supplier.name = @invoice.supplier.name
- if @invoice.delivery - if @invoice.delivery
%p %p
%b= t('simple_form.labels.invoice.delivery') + ':' %b= heading_helper(Invoice, :delivery) + ':'
= t('finance.invoices.linked', what_link: link_to(t('finance.invoices.linked_delivery'), [@invoice.supplier,@invoice.delivery])).html_safe = t('finance.invoices.linked', what_link: link_to(t('finance.invoices.linked_delivery'), [@invoice.supplier,@invoice.delivery])).html_safe
- if @invoice.order - if @invoice.order
%p %p
%b= t('simple_form.labels.invoice.order') + ':' %b= heading_helper(Invoice, :order) + ':'
= t('finance.invoices.linked', what_link: link_to(t('finance.invoices.linked_order'), @invoice.order)).html_safe = t('finance.invoices.linked', what_link: link_to(t('finance.invoices.linked_order'), @invoice.order)).html_safe
%p %p
%b= t('simple_form.labels.invoice.number') + ':' %b= heading_helper(Invoice, :number) + ':'
= @invoice.number = @invoice.number
%p %p
%b= t('simple_form.labels.invoice.date') + ':' %b= heading_helper(Invoice, :date) + ':'
= @invoice.date = @invoice.date
%p %p
%b= t('simple_form.labels.invoice.paid_on') + ':' %b= heading_helper(Invoice, :paid_on) + ':'
= @invoice.paid_on = @invoice.paid_on
%p %p
%b= t('simple_form.labels.invoice.amount') + ':' %b= heading_helper(Invoice, :amount) + ':'
= number_to_currency @invoice.amount = number_to_currency @invoice.amount
%p %p
%b= t('simple_form.labels.invoice.deposit') + ':' %b= heading_helper(Invoice, :deposit) + ':'
= number_to_currency @invoice.deposit = number_to_currency @invoice.deposit
%p %p
%b= t('simple_form.labels.invoice.deposit_credit') + ':' %b= heading_helper(Invoice, :deposit_credit) + ':'
= number_to_currency @invoice.deposit_credit = number_to_currency @invoice.deposit_credit
%p %p
%b= t('simple_form.labels.invoice.note') + ':' %b= heading_helper(Invoice, :note) + ':'
=h @invoice.note =h @invoice.note
= link_to t('ui.edit'), edit_finance_invoice_path(@invoice) = link_to t('ui.edit'), edit_finance_invoice_path(@invoice)

View file

@ -11,7 +11,7 @@
= f.input :unit = f.input :unit
- if @order_article.article.is_a?(StockArticle) - if @order_article.article.is_a?(StockArticle)
%div.alert Preise von Lagerartikeln können nicht geändert werden! %div.alert= t '.stock_alert'
- else - else
= simple_fields_for :article_price, @order_article.article_price do |f| = simple_fields_for :article_price, @order_article.article_price do |f|
= f.input :unit_quantity = f.input :unit_quantity

View file

@ -5,12 +5,12 @@
%thead %thead
%tr %tr
- if FoodsoftConfig[:use_nick] - if FoodsoftConfig[:use_nick]
%th= t 'simple_form.labels.user.nick' %th= heading_helper User, :nick
%th= t 'simple_form.labels.user.name' %th= heading_helper User, :name
%th= t 'simple_form.labels.user.email' %th= heading_helper User, :email
%th= t 'simple_form.labels.user.phone' %th= heading_helper User, :phone
%th= t 'simple_form.labels.user.ordergroup' %th= heading_helper User, :ordergroup
%th= t 'simple_form.labels.user.workgroup', count: 3 %th= heading_helper User, :workgroup, count: 3
%tbody %tbody
- for user in @users - for user in @users
%tr %tr

View file

@ -3,16 +3,20 @@
$(function() { $(function() {
#{data_to_js(@ordering_data)} #{data_to_js(@ordering_data)}
setGroupBalance(#{@ordering_data[:available_funds]}); setGroupBalance(#{@ordering_data[:available_funds]});
setCurrencyFormat("#{t('number.currency.format.separator')}", #{t('number.currency.format.precision')}, "#{t('number.currency.format.unit')}");
setMinimumBalance(#{FoodsoftConfig[:minimum_balance] or 0}); setMinimumBalance(#{FoodsoftConfig[:minimum_balance] or 0});
setToleranceBehaviour(#{FoodsoftConfig[:tolerance_is_costly]}); setToleranceBehaviour(#{FoodsoftConfig[:tolerance_is_costly]});
setStockit(#{@order.stockit?}); setStockit(#{@order.stockit?});
// create List for search-feature (using list.js, http://listjs.com)
var listjsResetPlugin = ['reset', {highlightClass: 'btn-primary'}];
var listjsDelayPlugin = ['delay', {delayedSearchTime: 500}];
new List(document.body, { valueNames: ['name'], engine: 'unlist', plugins: [listjsResetPlugin, listjsDelayPlugin] });
}); });
- title t('.title'), false - title t('.title'), false
.row-fluid .row-fluid
.well.pull-left .well.pull-left
%button{type: "button", class: "close", data: {dismiss: 'alert'}}= '&times;'.html_safe
%h2= @order.name %h2= @order.name
%dl.dl-horizontal %dl.dl-horizontal
- unless @order.note.blank? - unless @order.note.blank?
@ -35,8 +39,17 @@
%dd= number_to_currency(@ordering_data[:available_funds]) %dd= number_to_currency(@ordering_data[:available_funds])
.well.pull-right .well.pull-right
%button{type: "button", class: "close", data: {dismiss: 'alert'}}= '&times;'.html_safe
= render 'switch_order', current_order: @order = render 'switch_order', current_order: @order
.row-fluid
.well.clear
.form-search
.input-append
= text_field_tag :article, params[:article], placeholder: t('.search_article'), class: 'search-query delayed-search resettable'
%button.add-on.btn.reset-search{:type => :button, :title => t('.reset_article_search')}
%i.icon.icon-remove
= form_for @group_order do |f| = form_for @group_order do |f|
= f.hidden_field :lock_version = f.hidden_field :lock_version
= f.hidden_field :order_id = f.hidden_field :order_id
@ -59,9 +72,9 @@
%th(style="width:20px")= t '.available' %th(style="width:20px")= t '.available'
%th#col_required= t '.amount' %th#col_required= t '.amount'
%th{style: "width:15px;"}= t '.sum' %th{style: "width:15px;"}= t '.sum'
%tbody %tbody.list
- @order.articles_grouped_by_category.each do |category, order_articles| - @order.articles_grouped_by_category.each do |category, order_articles|
%tr.article-category %tr.list-heading.article-category
%td %td
= category = category
%i.icon-tag %i.icon-tag

View file

@ -4,4 +4,4 @@
= form.hidden_field :group_id = form.hidden_field :group_id
= form.input :email = form.input :email
= form.submit t('.action') = form.submit t('.action')
= link_to t('.back'), :back = link_to t('ui.or_cancel'), :back

View file

@ -22,7 +22,9 @@
Javascripts Javascripts
\================================================== \==================================================
/ Placed at the end of the document so the pages load faster / Placed at the end of the document so the pages load faster
:javascript
I18n = {locale: '#{j(I18n.locale.to_s)}'}
= javascript_include_tag "application" = javascript_include_tag "application"
:javascript
I18n.defaultLocale = "#{I18n.default_locale}";
I18n.locale = "#{I18n.locale}";
I18n.fallbacks = true;
= yield(:javascript) = yield(:javascript)

View file

@ -2,7 +2,7 @@
%h2= t '.title' %h2= t '.title'
- if ordergroup.not_enough_apples? - if ordergroup.not_enough_apples?
.alert .alert
= t '.not_enough_apples' = t '.not_enough_apples'
- unless Order.open.empty? - unless Order.open.empty?
%table.table.table-striped %table.table.table-striped
%thead %thead

View file

@ -3,5 +3,6 @@
= form.hidden_field :stock_article_id = form.hidden_field :stock_article_id
= "Menge (#{stock_change.stock_article.quantity_available})" = "Menge (#{stock_change.stock_article.quantity_available})"
= form.text_field :quantity, :size => 5, :autocomplete => 'off' = form.text_field :quantity, :size => 5, :autocomplete => 'off'
%b= stock_change.stock_article.name %span{:data => {:toggle => :tooltip, :title => render(:partial => 'shared/article_price_info', :locals => {:article => stock_change.stock_article})}}
= "(#{number_to_currency(stock_change.stock_article.price)} / #{stock_change.stock_article.unit})" %b= stock_change.stock_article.name
= "(#{number_to_currency(stock_change.stock_article.price)} / #{stock_change.stock_article.unit})"

View file

@ -11,7 +11,7 @@
%span.add-on % %span.add-on %
= f.input :deposit = f.input :deposit
- else - else
= f.input :price, :input_html => {:disabled => 'disabled'}, :hint => t('.form.price_hint') = f.input :price, :input_html => {:disabled => 'disabled'}, :hint => t('.price_hint')
= f.association :article_category = f.association :article_category
.form-actions .form-actions
= f.submit class: 'btn' = f.submit class: 'btn'

View file

@ -1,17 +0,0 @@
- title t('.stock_changes', :article_name => @stock_article.name)
%table.table.table-hover#stock_changes
%thead
%tr
%th= t '.datetime'
%th= t '.reason'
%th= t '.change_quantity'
%th= t '.new_quantity'
%tbody
- reversed_history = @stock_article.quantity_history.reverse
- @stock_changes.each_with_index do |stock_change, index|
%tr
%td= l stock_change.created_at
%td= link_to_stock_change_reason(stock_change)
%td= stock_change.quantity
%td= reversed_history[index]

View file

@ -45,7 +45,7 @@
%tbody %tbody
- for article in @stock_articles - for article in @stock_articles
%tr{:class => stock_article_classes(article), :id => "stockArticle-#{article.id}"} %tr{:class => stock_article_classes(article), :id => "stockArticle-#{article.id}"}
%td=h article.name %td= link_to article.name, article
%td= article.quantity %td= article.quantity
%td= article.quantity - article.quantity_available %td= article.quantity - article.quantity_available
%th= article.quantity_available %th= article.quantity_available
@ -56,7 +56,6 @@
%td= article.article_category.name %td= article.article_category.name
%td %td
= link_to t('ui.edit'), edit_stock_article_path(article), class: 'btn btn-mini' = link_to t('ui.edit'), edit_stock_article_path(article), class: 'btn btn-mini'
= link_to t('ui.history'), stock_article_history_path(article), class: 'btn btn-mini'
= link_to t('ui.delete'), article, :method => :delete, :confirm => t('.confirm_delete'), = link_to t('ui.delete'), article, :method => :delete, :confirm => t('.confirm_delete'),
class: 'btn btn-mini btn-danger', :remote => true class: 'btn btn-mini btn-danger', :remote => true
%p %p

View file

@ -0,0 +1,47 @@
- title @stock_article.name
.row-fluid
.span6
%dl.dl-horizontal
%dt= StockArticle.human_attribute_name 'supplier'
%dd= link_to @stock_article.supplier.name, @stock_article.supplier
%dt= StockArticle.human_attribute_name 'name'
%dd= @stock_article.name
%dt= StockArticle.human_attribute_name 'unit'
%dd= @stock_article.unit
%dt= StockArticle.human_attribute_name 'price'
%dd= number_to_currency @stock_article.price
%dt= StockArticle.human_attribute_name 'tax'
%dd= number_to_percentage @stock_article.tax
%dt= StockArticle.human_attribute_name 'deposit'
%dd= number_to_currency @stock_article.deposit
%dt= StockArticle.human_attribute_name 'fc_price'
%dd= number_to_currency @stock_article.fc_price
%dt= StockArticle.human_attribute_name 'article_category'
%dd= @stock_article.article_category.name
%dt= StockArticle.human_attribute_name 'note'
%dd= @stock_article.note
%dt= StockArticle.human_attribute_name 'quantity'
%dd= @stock_article.quantity
%dt= StockArticle.human_attribute_name 'quantity_available'
%dd= @stock_article.quantity_available
.form-actions
= link_to t('ui.edit'), edit_stock_article_path(@stock_article), class: 'btn'
.span6
%h2= t('.stock_changes')
%table.table.table-hover#stock_changes
%thead
%tr
%th= t '.datetime'
%th= t '.reason'
%th= t '.change_quantity'
%th= t '.new_quantity'
%tbody
- reversed_history = @stock_article.quantity_history.reverse
- @stock_changes.each_with_index do |stock_change, index|
%tr
%td= l stock_change.created_at
%td= link_to_stock_change_reason(stock_change)
%td= stock_change.quantity
%td= reversed_history[index]

View file

@ -1,7 +1,7 @@
= simple_form_for @supplier do |f| = simple_form_for @supplier do |f|
- if @supplier.shared_supplier - if @supplier.shared_supplier
.alert.alert-success .alert.alert-info
= t 'suppliers.shared_supplier_note' = t 'suppliers.shared_supplier_note'
= f.hidden_field :shared_supplier_id = f.hidden_field :shared_supplier_id
= f.input :name = f.input :name
= f.input :address = f.input :address

View file

@ -6,9 +6,9 @@
%table.table.table-striped %table.table.table-striped
%thead %thead
%tr %tr
%th= t 'simple_form.labels.supplier.name' %th= heading_helper Supplier, :name
%th= t 'simple_form.labels.supplier.phone' %th= heading_helper Supplier, :phone
%th= t 'simple_form.labels.supplier.customer_number' %th= heading_helper Supplier, :customer_number, short: true
%th %th
%th %th
%th %th

View file

@ -4,11 +4,11 @@
%table.table.table-striped %table.table.table-striped
%thead %thead
%tr %tr
%th= t 'simple_form.labels.supplier.name' %th= heading_helper Supplier, :name
%th= t 'simple_form.labels.supplier.address' %th= heading_helper Supplier, :address
%th= t 'simple_form.labels.supplier.note' %th= heading_helper Supplier, :note
%th= t 'simple_form.labels.supplier.delivery_days' %th= heading_helper Supplier, :delivery_days
%th= t 'simple_form.labels.supplier.is_subscribed' %th= heading_helper Supplier, :is_subscribed
%tbody %tbody
- for shared_supplier in @shared_suppliers - for shared_supplier in @shared_suppliers
%tr %tr

View file

@ -4,32 +4,32 @@
.span6 .span6
- if shared_supplier = @supplier.shared_supplier - if shared_supplier = @supplier.shared_supplier
.alert.alert-info .alert.alert-info
= t 'suppliers.shared_supplier_note' = t 'suppliers.shared_supplier_note'
%dl.dl-horizontal %dl.dl-horizontal
%dt= t('simple_form.labels.supplier.address') + ':' %dt= heading_helper(Supplier, :address) + ':'
%dd= @supplier.address %dd= @supplier.address
%dt= t('simple_form.labels.supplier.phone') + ':' %dt= heading_helper(Supplier, :phone) + ':'
%dd= @supplier.phone %dd= @supplier.phone
%dt= t('simple_form.labels.supplier.phone2') + ':' %dt= heading_helper(Supplier, :phone2) + ':'
%dd= @supplier.phone2 %dd= @supplier.phone2
%dt= t('simple_form.labels.supplier.fax') + ':' %dt= heading_helper(Supplier, :fax) + ':'
%dd= @supplier.fax %dd= @supplier.fax
%dt= t('simple_form.labels.supplier.email') + ':' %dt= heading_helper(Supplier, :email) + ':'
%dd= @supplier.email %dd= @supplier.email
%dt= t('simple_form.labels.supplier.url') + ':' %dt= heading_helper(Supplier, :url) + ':'
%dd= link_to @supplier.url, @supplier.url %dd= link_to @supplier.url, @supplier.url
%dt= t('simple_form.labels.supplier.contact_person') + ':' %dt= heading_helper(Supplier, :contact_person) + ':'
%dd= @supplier.contact_person %dd= @supplier.contact_person
%dt= t('simple_form.labels.supplier.customer_number') + ':' %dt= heading_helper(Supplier, :customer_number) + ':'
%dd= @supplier.customer_number %dd= @supplier.customer_number
%dt= t('simple_form.labels.supplier.delivery_days') + ':' %dt= heading_helper(Supplier, :delivery_days) + ':'
%dd= @supplier.delivery_days %dd= @supplier.delivery_days
%dt= t('simple_form.labels.supplier.order_howto') + ':' %dt= heading_helper(Supplier, :order_howto) + ':'
%dd= @supplier.order_howto %dd= @supplier.order_howto
%dt= t('simple_form.labels.supplier.note') + ':' %dt= heading_helper(Supplier, :note) + ':'
%dd= @supplier.note %dd= @supplier.note
%dt= t('simple_form.labels.supplier.min_order_quantity') + ':' %dt= heading_helper(Supplier, :min_order_quantity) + ':'
%dd= @supplier.min_order_quantity %dd= @supplier.min_order_quantity
.clearfix .clearfix
@ -43,8 +43,8 @@
%table.table.table-horizontal %table.table.table-horizontal
%thead %thead
%tr %tr
%th= t 'simple_form.labels.defaults.date' %th= heading_helper Delivery, :date
%th= t 'simple_form.labels.defaults.amount' %th= heading_helper Delivery, :amount
%tbody %tbody
- for delivery in @deliveries - for delivery in @deliveries
%tr %tr

View file

@ -3,22 +3,22 @@
%section %section
%dl.dl-horizontal %dl.dl-horizontal
%dt= t 'simple_form.labels.task.name' %dt= Task.human_attribute_name(:name)
%dd= @task.name %dd= @task.name
- if @task.description.present? - if @task.description.present?
%dt= t 'simple_form.labels.defaults.description' %dt= Task.human_attribute_name(:description)
%dd= simple_format(@task.description) %dd= simple_format(@task.description)
- if @task.due_date.present? - if @task.due_date.present?
%dt= t '.due_date' %dt= Task.human_attribute_name(:due_date)
%dd %dd
= format_date(@task.due_date) = format_date(@task.due_date)
- if @task.periodic? - if @task.periodic?
%i.icon-repeat{title: t('tasks.repeated')} %i.icon-repeat{title: t('tasks.repeated')}
%dt= t 'simple_form.labels.task.duration' %dt= Task.human_attribute_name(:duration)
%dd= t('.hours', count: @task.duration) %dd= t('.hours', count: @task.duration)
%dt= t 'simple_form.labels.task.user_list' %dt= Task.human_attribute_name(:user_list)
%dd= task_assignments(@task) %dd= task_assignments(@task)
%dt= t 'simple_form.labels.task.workgroup' %dt= Task.human_attribute_name(:workgroup)
%dd %dd
- if @task.workgroup - if @task.workgroup
= link_to @task.workgroup.name, workgroup_tasks_path(workgroup_id: @task.workgroup_id) = link_to @task.workgroup.name, workgroup_tasks_path(workgroup_id: @task.workgroup_id)
@ -30,7 +30,7 @@
- unless @task.done? - unless @task.done?
= link_to t('.mark_done'), set_done_task_path(@task), method: :post, class: 'btn' = link_to t('.mark_done'), set_done_task_path(@task), method: :post, class: 'btn'
= link_to t('ui.edit'), edit_task_path(@task), class: 'btn' = link_to t('ui.edit'), edit_task_path(@task), class: 'btn'
= link_to t('ui.delete'), task_path(@task), :method => :delete, :confirm => "Die Aufgabe wirklich löschen?", = link_to t('ui.delete'), task_path(@task), :method => :delete, :confirm => t('.confirm_delete_single'),
class: 'btn btn-danger' class: 'btn btn-danger'
- if @task.periodic? - if @task.periodic?
= link_to t('.delete_group'), task_path(@task, periodic: true), method: :delete, = link_to t('.delete_group'), task_path(@task, periodic: true), method: :delete,

View file

@ -30,7 +30,8 @@ module Foodsoft
# config.time_zone = 'Central Time (US & Canada)' # config.time_zone = 'Central Time (US & Canada)'
# Internationalization. # Internationalization.
config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')] config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '*.yml')]
config.i18n.available_locales = Pathname.glob(Rails.root.join('config', 'locales', '??{-*,}.yml')).map{|p| p.basename('.yml').to_s }
config.i18n.default_locale = :en config.i18n.default_locale = :en
# Configure the default encoding used in templates for Ruby 1.9. # Configure the default encoding used in templates for Ruby 1.9.
@ -59,7 +60,8 @@ module Foodsoft
# Version of your assets, change this if you want to expire all your assets # Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.0' config.assets.version = '1.0'
# Do not enable database connection when precompiling assets # It would be nice not to enable database connection when precompiling assets,
config.assets.initialize_on_precompile = false # but i18n-js requires initialization, that's why it's on.
config.assets.initialize_on_precompile = true
end end
end end

View file

@ -35,6 +35,9 @@ Foodsoft::Application.configure do
# Expands the lines which load the assets # Expands the lines which load the assets
config.assets.debug = true config.assets.debug = true
# Required for i18n-js
config.assets.initialize_on_precompile = true
# Configure hostname for action mailer # Configure hostname for action mailer
config.action_mailer.default_url_options = { host: 'localhost:3000' } config.action_mailer.default_url_options = { host: 'localhost:3000' }
@ -42,4 +45,4 @@ Foodsoft::Application.configure do
# Mailcatcher can be installed by gem install mailcatcher # Mailcatcher can be installed by gem install mailcatcher
config.action_mailer.delivery_method = :smtp config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = { address: "localhost", port: 1025 } config.action_mailer.smtp_settings = { address: "localhost", port: 1025 }
end end

View file

@ -11,6 +11,9 @@ Foodsoft::Application.configure do
config.serve_static_assets = true config.serve_static_assets = true
config.static_cache_control = "public, max-age=3600" config.static_cache_control = "public, max-age=3600"
# Required for i18n-js
config.assets.initialize_on_precompile = true
# Log error messages when you accidentally call methods on nil # Log error messages when you accidentally call methods on nil
config.whiny_nils = true config.whiny_nils = true

4
config/i18n-js.yml Normal file
View file

@ -0,0 +1,4 @@
# only serve selected strings for i18n-js to keep filesize down
translations:
- file: 'app/assets/javascripts/i18n/translations.js'
only: ['*.js.*', '*.number.*', '*.date.formats.*']

View file

@ -1,7 +1,15 @@
# ClientSideValidations Initializer # ClientSideValidations Initializer
require 'client_side_validations/simple_form' if defined?(::SimpleForm) # Uncomment to disable uniqueness validator, possible security issue
require 'client_side_validations/formtastic' if defined?(::Formtastic) # Disabled because of possible security issue and because of bug
# https://github.com/bcardarella/client_side_validations/pull/532
ClientSideValidations::Config.disabled_validators = [:uniqueness]
# Uncomment to validate number format with current I18n locale
# Foodsoft is currently using localize_input which is activated on certain
# fields only, meaning we can't globally turn this on. The non-i18n number
# format is still supported - so for now keep false.
# ClientSideValidations::Config.number_format_with_locale = true
# Uncomment the following block if you want each input field to have the validation messages attached. # Uncomment the following block if you want each input field to have the validation messages attached.
# ActionView::Base.field_error_proc = Proc.new do |html_tag, instance| # ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|

View file

@ -14,13 +14,15 @@ url_options.merge!({:port => FoodsoftConfig[:port]}) if FoodsoftConfig[:port]
Foodsoft::Application.configure do Foodsoft::Application.configure do
config.action_mailer.default_url_options = url_options config.action_mailer.default_url_options = url_options
if Rails.env !~ /development|test/ if %w(production).include? Rails.env
# Configuration of the exception_notification plugin # Configuration of the exception_notification plugin
# Mailadresses are set in config/app_config.yml # Mailadresses are set in config/app_config.yml
config.middleware.use ExceptionNotifier, config.middleware.use ExceptionNotification::Rack,
:email_prefix => FoodsoftConfig[:notification]['email_prefix'], :email => {
:sender_address => FoodsoftConfig[:notification]['sender_address'], :email_prefix => FoodsoftConfig[:notification]['email_prefix'],
:exception_recipients => FoodsoftConfig[:notification]['error_recipients'] :sender_address => FoodsoftConfig[:notification]['sender_address'],
:exception_recipients => FoodsoftConfig[:notification]['error_recipients']
}
end end
end end

View file

@ -1,98 +1,142 @@
de: de:
activemodel:
errors:
format: ! '%{attribute} %{message}'
general: Ein Problem ist aufgetreten.
general_again: Ein Fehler ist aufgetreten. Bitte erneut versuchen.
general_msg: ! 'Ein Fehler ist aufgetreten: %{msg}'
messages:
accepted: muss akzeptiert werden
blank: muss ausgefüllt werden
confirmation: stimmt nicht mit der Bestätigung überein
empty: muss ausgefüllt werden
equal_to: muss genau %{count} sein
even: muss gerade sein
exclusion: ist nicht verfügbar
greater_than: muss größer als %{count} sein
greater_than_or_equal_to: muss größer oder gleich %{count} sein
inclusion: ist kein gültiger Wert
invalid: ist nicht gültig
less_than: muss kleiner als %{count} sein
less_than_or_equal_to: muss kleiner oder gleich %{count} sein
not_a_number: ist keine Zahl
not_an_integer: muss ganzzahlig sein
odd: muss ungerade sein
record_invalid: ! 'Gültigkeitsprüfung ist fehlgeschlagen: %{errors}'
taken: ist bereits vergeben
taken_with_deleted: ist bereits vergeben (eine gelöschte Gruppe)
too_long: ist zu lang (nicht mehr als %{count} Zeichen)
too_short: ist zu kurz (nicht weniger als %{count} Zeichen)
wrong_length: hat die falsche Länge (muss genau %{count} Zeichen haben)
template:
body: ! 'Bitte überprüfen Sie die folgenden Felder:'
header:
one: ! 'Konnte %{model} nicht speichern: ein Fehler.'
other: ! 'Konnte %{model} nicht speichern: %{count} Fehler.'
activerecord: activerecord:
attributes: attributes:
article: article:
article_category: Kategorie article_category: Kategorie
availability: Artikel ist verfügbar? availability: Artikel ist verfügbar?
availability_short: verf.
deposit: Pfand deposit: Pfand
fc_price: Endpreis fc_price: Endpreis
fc_share: FC-Aufschlag fc_price_short:
fc_share: FoodCoop-Aufschlag
fc_share_short: FC-Aufschlag
gross_price: Bruttopreis gross_price: Bruttopreis
manufacturer: Produzent
name: Name
note: Notiz
order_number: Bestellnummer
origin: Herkunft
price: Nettopreis price: Nettopreis
supplier: Lieferantin
tax: MwSt tax: MwSt
unit: Einheit unit: Einheit
unit_quantity: Gebindegröße unit_quantity: Gebindegröße
unit_quantity_short: GebGr
article_category:
description: Beschreibung
name: Name
delivery:
delivered_on: Lieferdatum
note: Notiz
supplier: Lieferantin
financial_transaction: financial_transaction:
amount: Betrag amount: Betrag
note: Notiz note: Notiz
group_order_article:
ordergroup_id: Bestellgruppe
result: Menge
invoice:
amount: Betrag
date: Rechnungsdatum
delivery: Lieferung
deposit: Pfand berechnet
deposit_credit: Pfand gutgeschrieben
note: Notiz
number: Nummer
order: Bestellung
paid_on: Bezahlt am
supplier: Lieferant
message:
body: Inhalt
group_id: Gruppe
private: Privat
recipient_tokens: Empfänger_innen
sent_to_all: An alle Mitglieder schicken
subject: Betreff
order:
ends: Endet am
note: Notiz
starts: Läuft vom
order_article:
units_to_order: Menge
update_current_price: Globalen Preis aktualisieren
order_comment:
text: Kommentiere diese Bestellung ...
ordergroup:
contact_address: Adresse
contact_person: Kontaktperson
contact_phone: Telefon
description: Beschreibung
ignore_apple_restriction: Bestellstop bei zu wenig Äpfeln ignorieren
name: Name
user_tokens: Mitglieder
page:
body: Inhalt
parent_id: Oberseite
title: Titel
stock_article: stock_article:
price: Nettopreis price: Nettopreis
quantity: Lagerbestand
quantity_available: Verfügbarer Bestand
supplier: Lieferant
stock_taking:
date: Datum
note: Notiz
supplier:
address: Adresse
contact_person: Ansprechparter_in
customer_number: Kundennummer
customer_number_short: Kundennr.
delivery_days: Liefertage
email: Email
fax: FAX
is_subscribed: abonniert?
min_order_quantity: Mindestbestellmenge
name: Name
note: Notiz
order_howto: Howto Bestellen
phone: Telefon
phone2: Telefon 2
url: Homepage
task:
description: Beschreibung
done: Erledigt?
due_date: Wann erledigen?
duration: Dauer
name: Name
required_users: Anzahl
user_list: Verantwortliche
workgroup: Arbeitsgruppe
user: user:
email: Email
first_name: Vorname first_name: Vorname
last_name: Nachname
name: Name
nick: Benutzername
ordergroup: Bestellgruppe
password: Passwort password: Passwort
password_confirmation: Passwort wiederholen
phone: Telefon
workgroup:
one: Arbeitsgruppe
other: Arbeitsgruppen
workgroup:
description: Beschreibung
name: Name
next_weekly_tasks_number: Für wieviel Wochen im Voraus sollen Aufgaben erstellt werden?
role_admin: Administration
role_article_meta: Artikeldatenbank
role_finance: Finanzen
role_orders: Bestellverwaltung
role_suppliers: Lieferanten
user_tokens: Mitglieder
errors: errors:
format: ! '%{attribute} %{message}'
general: Ein Problem ist aufgetreten.
general_again: Ein Fehler ist aufgetreten. Bitte erneut versuchen.
general_msg: ! 'Ein Fehler ist aufgetreten: %{msg}'
has_many_left: ist noch mit einem/r %{collection} verknüpft! has_many_left: ist noch mit einem/r %{collection} verknüpft!
messages:
accepted: muss akzeptiert werden
blank: muss ausgefüllt werden
confirmation: stimmt nicht mit der Bestätigung überein
empty: muss ausgefüllt werden
equal_to: muss genau %{count} sein
even: muss gerade sein
exclusion: ist nicht verfügbar
greater_than: muss größer als %{count} sein
greater_than_or_equal_to: muss größer oder gleich %{count} sein
inclusion: ist kein gültiger Wert
invalid: ist nicht gültig
less_than: muss kleiner als %{count} sein
less_than_or_equal_to: muss kleiner oder gleich %{count} sein
not_a_number: ist keine Zahl
not_an_integer: muss ganzzahlig sein
odd: muss ungerade sein
record_invalid: ! 'Gültigkeitsprüfung ist fehlgeschlagen: %{errors}'
taken: ist bereits vergeben
taken_with_deleted: ist bereits vergeben (eine gelöschte Gruppe)
too_long: ist zu lang (nicht mehr als %{count} Zeichen)
too_short: ist zu kurz (nicht weniger als %{count} Zeichen)
wrong_length: hat die falsche Länge (muss genau %{count} Zeichen haben)
models: models:
task: task:
attributes: attributes:
done: done:
exclusion: erledigte Aufgaben können nicht wöchentlich wiederholt werden exclusion: erledigte Aufgaben können nicht wöchentlich wiederholt werden
template:
body: ! 'Bitte überprüfen Sie die folgenden Felder:'
header:
one: ! 'Konnte %{model} nicht speichern: ein Fehler.'
other: ! 'Konnte %{model} nicht speichern: %{count} Fehler.'
models: models:
article: Artikel article: Artikel
article_category: Artikelkategorie article_category: Artikelkategorie
@ -212,6 +256,11 @@ de:
workgroups: workgroups:
members: Mitglieder members: Mitglieder
name: Name name: Name
application:
controller:
error_authn:
error_denied:
error_members_only: Diese Aktion ist nur für Mitglieder der Gruppe erlaubt!
article_categories: article_categories:
create: create:
notice: Die Kategorie wurde gespeichert notice: Die Kategorie wurde gespeichert
@ -305,18 +354,21 @@ de:
error_nosel: Du hast keine Artikel ausgewählt error_nosel: Du hast keine Artikel ausgewählt
parse_upload: parse_upload:
body: <p><i>Bitte überprufe die engelesenen Artikel.</i></p> <p><i>Achtung, momentan gibt es keine Überprüfung auf doppelte Artikel.</i></p> body: <p><i>Bitte überprufe die engelesenen Artikel.</i></p> <p><i>Achtung, momentan gibt es keine Überprüfung auf doppelte Artikel.</i></p>
title:
sync:
outlist: outlist:
alert_used: Achtung, %{article} wird gerade in einer laufenden Bestellung verwendet. Bitte erst Bestellung anpassen.
body: ! 'Folgende Artikel wurden ausgelistet und werden <b>gelöscht</b>:' body: ! 'Folgende Artikel wurden ausgelistet und werden <b>gelöscht</b>:'
body_skip: Es müssen keine Artikel gelöscht werden. body_skip: Es müssen keine Artikel gelöscht werden.
title: Auslisten ... title: Auslisten ...
price_short: Preis price_short: Preis
submit: Alle löschen/aktualisieren submit: Alle synchronisieren
title: Artikel mit externer Datenbank synchronisieren title: Artikel mit externer Datenbank synchronisieren
unit_quantity_short: GebGr unit_quantity_short: GebGr
update: update:
body: <p><i>Jeder Artikel wird doppelt angezeigt. Die alten Werte sind grau und die Textfelder sind mit den aktuellen Werten vorausgefüllt.</i></p> <p><i>Abweichungen zu den alten Artikeln sind gelb markiert.</i></p> body: ! 'Jeder Artikel wird doppelt angezeigt: die alten Werte sind grau und die Textfelder sind mit den aktuellen Werten vorausgefüllt. Abweichungen zu den alten Artikeln sind gelb markiert.'
title: Aktualisieren ... title: Aktualisieren ...
update_msg: ! 'Artikel müssen aktualisiert werden:' update_msg: ! '%{count} Artikel müssen aktualisiert werden.'
upload: upload:
body: <p>Die Datei muss eine Textdatei mit der Endung '.csv' sein. Die erste Zeile wird beim Einlesen ignoriert.</p> <p>Die Felder müssen mit einem Semikolon (';') getrennt und der Text mit doppelten Anführungszeichen ("Text...") umklammert werden.</p> <p>Als Zeichensatz wird UTF-8 erwartet. Korrekte Reihenfolge der Spalten:</p> body: <p>Die Datei muss eine Textdatei mit der Endung '.csv' sein. Die erste Zeile wird beim Einlesen ignoriert.</p> <p>Die Felder müssen mit einem Semikolon (';') getrennt und der Text mit doppelten Anführungszeichen ("Text...") umklammert werden.</p> <p>Als Zeichensatz wird UTF-8 erwartet. Korrekte Reihenfolge der Spalten:</p>
fields: fields:
@ -326,102 +378,6 @@ de:
file_label: Bitte wähle eine kompatible Datei aus file_label: Bitte wähle eine kompatible Datei aus
submit: Datei hochladen submit: Datei hochladen
title: ! '%{supplier} / Artikel hochladen' title: ! '%{supplier} / Artikel hochladen'
date:
abbr_day_names:
- So
- Mo
- Di
- Mi
- Do
- Fr
- Sa
abbr_month_names:
-
- Jan
- Feb
- Mär
- Apr
- Mai
- Jun
- Jul
- Aug
- Sep
- Okt
- Nov
- Dez
day_names:
- Sonntag
- Montag
- Dienstag
- Mittwoch
- Donnerstag
- Freitag
- Samstag
formats:
default: ! '%d.%m.%Y'
long: ! '%e. %B %Y'
short: ! '%e. %b'
month_names:
-
- Januar
- Februar
- März
- April
- Mai
- Juni
- Juli
- August
- September
- Oktober
- November
- Dezember
order:
- :day
- :month
- :year
datetime:
distance_in_words:
about_x_hours:
one: etwa eine Stunde
other: etwa %{count} Stunden
about_x_months:
one: etwa ein Monat
other: etwa %{count} Monate
about_x_years:
one: etwa ein Jahr
other: etwa %{count} Jahre
almost_x_years:
one: fast ein Jahr
other: fast %{count} Jahre
half_a_minute: eine halbe Minute
less_than_x_minutes:
one: weniger als eine Minute
other: weniger als %{count} Minuten
less_than_x_seconds:
one: weniger als eine Sekunde
other: weniger als %{count} Sekunden
over_x_years:
one: mehr als ein Jahr
other: mehr als %{count} Jahre
x_days:
one: ein Tag
other: ! '%{count} Tage'
x_minutes:
one: eine Minute
other: ! '%{count} Minuten'
x_months:
one: ein Monat
other: ! '%{count} Monate'
x_seconds:
one: eine Sekunde
other: ! '%{count} Sekunden'
prompts:
day: Tag
hour: Stunden
minute: Minuten
month: Monat
second: Sekunden
year: Jahr
deliveries: deliveries:
add_stock_change: add_stock_change:
how_many_units: Wie viele Einheiten (%{unit}) des Artikels »%{name}« liefern? how_many_units: Wie viele Einheiten (%{unit}) des Artikels »%{name}« liefern?
@ -521,38 +477,9 @@ de:
title: ! 'Sortiermatrix der Bestellung: %{name}, beendet am %{date}' title: ! 'Sortiermatrix der Bestellung: %{name}, beendet am %{date}'
total: Insgesamt %{count} Artikel total: Insgesamt %{count} Artikel
errors: errors:
format: ! '%{attribute} %{message}'
general: Ein Problem ist aufgetreten. general: Ein Problem ist aufgetreten.
general_again: Ein Fehler ist aufgetreten. Bitte erneut versuchen. general_again: Ein Fehler ist aufgetreten. Bitte erneut versuchen.
general_msg: ! 'Ein Fehler ist aufgetreten: %{msg}' general_msg: ! 'Ein Fehler ist aufgetreten: %{msg}'
messages:
accepted: muss akzeptiert werden
blank: muss ausgefüllt werden
confirmation: stimmt nicht mit der Bestätigung überein
empty: muss ausgefüllt werden
equal_to: muss genau %{count} sein
even: muss gerade sein
exclusion: ist nicht verfügbar
greater_than: muss größer als %{count} sein
greater_than_or_equal_to: muss größer oder gleich %{count} sein
inclusion: ist kein gültiger Wert
invalid: ist nicht gültig
less_than: muss kleiner als %{count} sein
less_than_or_equal_to: muss kleiner oder gleich %{count} sein
not_a_number: ist keine Zahl
not_an_integer: muss ganzzahlig sein
odd: muss ungerade sein
record_invalid: ! 'Gültigkeitsprüfung ist fehlgeschlagen: %{errors}'
taken: ist bereits vergeben
taken_with_deleted: ist bereits vergeben (eine gelöschte Gruppe)
too_long: ist zu lang (nicht mehr als %{count} Zeichen)
too_short: ist zu kurz (nicht weniger als %{count} Zeichen)
wrong_length: hat die falsche Länge (muss genau %{count} Zeichen haben)
template:
body: ! 'Bitte überprüfen Sie die folgenden Felder:'
header:
one: ! 'Konnte %{model} nicht speichern: ein Fehler.'
other: ! 'Konnte %{model} nicht speichern: %{count} Fehler.'
feedback: feedback:
create: create:
notice: Das Feedback wurde erfolgreich verschickt. Vielen Dank! notice: Das Feedback wurde erfolgreich verschickt. Vielen Dank!
@ -644,11 +571,13 @@ de:
create: create:
notice: Rechnung wurde erstellt. notice: Rechnung wurde erstellt.
financial_transactions: financial_transactions:
create: controller:
notice: Die Transaktion wurde gespeichert. create:
create_collection: notice: Die Transaktion wurde gespeichert.
alert: ! 'Ein Fehler ist aufgetreten: %{error}' create_collection:
notice: Alle Transaktionen wurden gespeichert. alert: ! 'Ein Fehler ist aufgetreten: %{error}'
error_note_required: Notiz wird benötigt!
notice: Alle Transaktionen wurden gespeichert.
index: index:
balance: ! 'Kontostand: %{balance}' balance: ! 'Kontostand: %{balance}'
last_updated_at: (zuletzt aktualisiert vor %{when}) last_updated_at: (zuletzt aktualisiert vor %{when})
@ -677,6 +606,7 @@ de:
group_order_articles: group_order_articles:
form: form:
amount_change_for: Mengenänderung für %{article} amount_change_for: Mengenänderung für %{article}
result_hint: ! 'Einheit: %{unit}'
index: index:
amount: Betrag amount: Betrag
amount_fc: Betrag(FC) amount_fc: Betrag(FC)
@ -712,6 +642,7 @@ de:
title: Rechnung %{number} title: Rechnung %{number}
order_articles: order_articles:
edit: edit:
stock_alert: Preise von Lagerartikeln können nicht geändert werden!
title: Artikel aktualisieren title: Artikel aktualisieren
new: new:
title: Neuer gelieferter Artikel die Bestellung title: Neuer gelieferter Artikel die Bestellung
@ -787,6 +718,8 @@ de:
new_funds: Neuer Kontostand new_funds: Neuer Kontostand
note: Notiz note: Notiz
price: Preis price: Preis
reset_article_search: Suche zurücksetzen
search_article: Artikel suchen...
sum: Summe sum: Summe
sum_amount: ! 'Gesamtbestellmenge bisher:' sum_amount: ! 'Gesamtbestellmenge bisher:'
supplier: Lieferant supplier: Lieferant
@ -875,15 +808,11 @@ de:
option_choose: Lieferantin/Lager auswählen option_choose: Lieferantin/Lager auswählen
option_stock: Lager option_stock: Lager
order_pdf: PDF erstellen order_pdf: PDF erstellen
select:
prompt: Bitte wählen
submit: submit:
create: ! '%{model} speichern'
invite: invite:
create: Einladung verschicken create: Einladung verschicken
message: message:
create: Nachricht verschicken create: Nachricht verschicken
update: Änderungen speichern
tasks: tasks:
required_users: Es fehlen %{count} Mitstreiterinnen! required_users: Es fehlen %{count} Mitstreiterinnen!
home: home:
@ -971,9 +900,11 @@ de:
title: Person einladen title: Person einladen
new: new:
action: Einlading abschicken action: Einlading abschicken
back: oder zurück
body: <p>Hier kannst du eine Person in die Gruppe <b>%{group}</b> einladen, die noch nicht Mitglied der Foodcoop ist.</p> body: <p>Hier kannst du eine Person in die Gruppe <b>%{group}</b> einladen, die noch nicht Mitglied der Foodcoop ist.</p>
success: Benutzerin wurde erfolgreich eingeladen. success: Benutzerin wurde erfolgreich eingeladen.
js:
ordering:
confirm_change: Änderungen an dieser Bestellung gehen verloren, wenn zu einer anderen Bestellung gewechselt wird. Möchtest Du trotzdem wechseln?
layouts: layouts:
application1: application1:
title: Foodsoft - %{title} title: Foodsoft - %{title}
@ -1218,57 +1149,6 @@ de:
home: Startseite home: Startseite
title: Wiki title: Wiki
workgroups: Arbeitsgruppen workgroups: Arbeitsgruppen
number:
currency:
format:
delimiter: .
format: ! '%n %u'
precision: 2
separator: ! ','
significant: false
strip_insignificant_zeros: false
unit:
format:
delimiter: .
precision: 2
separator: ! ','
significant: false
strip_insignificant_zeros: false
human:
decimal_units:
format: ! '%n %u'
units:
billion:
one: Milliarde
other: Milliarden
million: Millionen
quadrillion:
one: Billiarde
other: Billiarden
thousand: Tausend
trillion: Billionen
unit:
format:
delimiter:
precision: 1
significant: true
strip_insignificant_zeros: true
storage_units:
format: ! '%n %u'
units:
byte:
one: Byte
other: Bytes
gb: GB
kb: KB
mb: MB
tb: TB
percentage:
format:
delimiter:
precision:
format:
delimiter:
ordergroups: ordergroups:
edit: edit:
title: Bestellgruppe bearbeiten title: Bestellgruppe bearbeiten
@ -1293,7 +1173,6 @@ de:
fax: fax:
amount: Menge amount: Menge
articles: Artikel articles: Artikel
customer_number: Kundennummer
delivery_day: Liefertag delivery_day: Liefertag
heading: Bestellung für %{name} heading: Bestellung für %{name}
name: Name name: Name
@ -1532,7 +1411,7 @@ de:
message: message:
private: Nachricht erscheint nicht im Foodsoft Posteingang private: Nachricht erscheint nicht im Foodsoft Posteingang
order_article: order_article:
units_to_order: Anzahl gelieferter Gebinde units_to_order: Wenn Du die Gesamtanzahl gelieferter Gebinde änderst, musst Du auch die individuelle Anzahl der einzelnen Bestellgruppen anpassen, indem Du auf den Artikelnamen klickst. Sie werden nicht automatisch neuberechnet und andernfalls werden den Bestellgruppen Artikel in Rechnung gestellt, die nicht geliefert wurden!
update_current_price: Ändert auch den Preis für aktuelle Bestellungen update_current_price: Ändert auch den Preis für aktuelle Bestellungen
stock_article: stock_article:
copy_stock_article: copy_stock_article:
@ -1547,74 +1426,6 @@ de:
required_users: Wieviel Benutzerinnen werden insgesamt benötigt? required_users: Wieviel Benutzerinnen werden insgesamt benötigt?
tax: In Prozent, Standard sind 7,0 tax: In Prozent, Standard sind 7,0
labels: labels:
article:
article_category: Kategorie
manufacturer: Produzent
name: Name
note: Notiz
origin: Herkunft
unit: Einheit
article_category:
description: Beschreibung
name: Name
defaults:
amount: Betrag
date: Datum
deposit: Pfand
description: Beschreibung
email: E-Mail
note: Notiz
order_number: Bestellnummer
ordergroup: Bestellgruppe
password: Passwort
password_confirmation: Passwort wiederholen
phone: Telefon
price: Preis (netto)
tax: MwSt
title: Titel
unit_quantity: Gebindegröße
user_tokens: Mitglieder
delivery:
delivered_on: Lieferdatum
supplier: Lieferantin
group_order_article:
ordergroup_id: Bestellgruppe
result: Menge
invoice:
amount: Betrag
date: Rechnungsdatum
delivery: Lieferung
deposit: Pfand berechnet
deposit_credit: Pfand gutgeschrieben
note: Notiz
number: Nummer
order: Bestellung
paid_on: Bezahlt am
supplier: Lieferant
message:
body: Inhalt
group_id: Gruppe
private: Privat
recipient_tokens: Empfänger_innen
sent_to_all: An alle Mitglieder schicken
subject: Betreff
order:
ends: Endet am
starts: Läuft vom
order_article:
units_to_order: Menge
update_current_price: Globalen Preis aktualisieren
order_comment:
text: Kommentiere diese Bestellung ...
ordergroup:
contact_address: Adresse
contact_person: Kontaktperson
contact_phone: Telefon
ignore_apple_restriction: Bestellstop bei zu wenig Äpfeln ignorieren
name: Name
page:
body: Inhalt
parent_id: Oberseite
settings: settings:
messages: messages:
send_as_email: Bekomme Nachrichten als Emails. send_as_email: Bekomme Nachrichten als Emails.
@ -1630,48 +1441,6 @@ de:
settings_group: settings_group:
messages: Nachrichten messages: Nachrichten
privacy: Privatsphäre privacy: Privatsphäre
stock_article:
supplier: Lieferant
supplier:
address: Adresse
contact_person: Ansprechparter_in
customer_number: Kundennummer
delivery_days: Liefertage
email: Email
fax: FAX
is_subscribed: abonniert?
min_order_quantity: Mindestbestellmenge
name: Name
note: Notiz
order_howto: Howto Bestellen
phone: Telefon
phone2: Telefon 2
url: Homepage
task:
done: Erledigt?
due_date: Wann erledigen?
duration: Dauer
name: Name
required_users: Anzahl
user_list: Verantwortliche
workgroup: Arbeitsgruppe
user:
email: Email
last_name: Nachname
name: Name
nick: Benutzername
ordergroup: Bestellgruppe
phone: Telefon
workgroup:
one: Arbeitsgruppe
other: Arbeitsgruppen
workgroup:
next_weekly_tasks_number: Für wieviel Wochen im Voraus sollen Aufgaben erstellt werden?
role_admin: Administration
role_article_meta: Artikeldatenbank
role_finance: Finanzen
role_orders: Bestellverwaltung
role_suppliers: Lieferanten
'no': Nein 'no': Nein
options: options:
settings: settings:
@ -1725,15 +1494,6 @@ de:
title: Lagerartikel bearbeiten title: Lagerartikel bearbeiten
form: form:
price_hint: Um Chaos zu vermeiden können bis auf weiteres die Preise von angelegten Lagerartikeln nicht mehr verändert werden. price_hint: Um Chaos zu vermeiden können bis auf weiteres die Preise von angelegten Lagerartikeln nicht mehr verändert werden.
history:
change_quantity: Veränderung
datetime: Zeitpunkt
delivery: Lieferung
new_quantity: Neuer Bestand
order: Bestellung
reason: Ereignis
stock_changes: Verlauf anzeigen für »%{article_name}«
stock_taking: Inventur
index: index:
article: article:
article: Artikel article: Artikel
@ -1759,6 +1519,15 @@ de:
new: new:
search_text: ! 'Suche nache Artikeln aus allen Katalogen:' search_text: ! 'Suche nache Artikeln aus allen Katalogen:'
title: Neuen Lagerartikel anlegen title: Neuen Lagerartikel anlegen
show:
change_quantity: Veränderung
datetime: Zeitpunkt
delivery: Lieferung
new_quantity: Neuer Bestand
order: Bestellung
reason: Ereignis
stock_changes: Verlauf des Lagerbestands
stock_taking: Inventur
stock_create: stock_create:
notice: Lagerartikel wurde gespeichert. notice: Lagerartikel wurde gespeichert.
stock_update: stock_update:
@ -1794,11 +1563,6 @@ de:
show_deliveries: Zeige alle Lieferungen show_deliveries: Zeige alle Lieferungen
update: update:
notice: Lieferant wurde aktualisiert notice: Lieferant wurde aktualisiert
support:
array:
last_word_connector: ! ' und '
two_words_connector: ! ' und '
words_connector: ! ', '
tasks: tasks:
accept: accept:
notice: Du hast die Aufgabe übernommen notice: Du hast die Aufgabe übernommen
@ -1854,8 +1618,8 @@ de:
show: show:
accept_task: Aufgabe übernehmen accept_task: Aufgabe übernehmen
confirm_delete_group: Diese und alle folgenden wöchentlichen Aufgaben wirklich löschen? confirm_delete_group: Diese und alle folgenden wöchentlichen Aufgaben wirklich löschen?
confirm_delete_single: Die Aufgabe wirklich löschen?
delete_group: Aufgabe und folgende löschen delete_group: Aufgabe und folgende löschen
due_date: Fälligkeitsdatum
hours: ! '%{count}h' hours: ! '%{count}h'
mark_done: Als erledigt markieren mark_done: Als erledigt markieren
reject_task: Aufgabe ablehnen reject_task: Aufgabe ablehnen
@ -1872,18 +1636,10 @@ de:
workgroup: workgroup:
title: Aufgaben für %{workgroup} title: Aufgaben für %{workgroup}
title_all: Alle Aufgaben der Gruppe title_all: Alle Aufgaben der Gruppe
time:
am: vormittags
formats:
default: ! '%A, %d. %B %Y, %H:%M Uhr'
long: ! '%A, %d. %B %Y, %H:%M Uhr'
short: ! '%d. %B, %H:%M Uhr'
pm: nachmittags
ui: ui:
close: Schließen close: Schließen
delete: Löschen delete: Löschen
edit: Bearbeiten edit: Bearbeiten
history: Verlauf anzeigen
marks: marks:
close: ! '&times;' close: ! '&times;'
success: <i class="icon icon-ok"></i> success: <i class="icon icon-ok"></i>

View file

@ -1,98 +1,142 @@
en: en:
activemodel:
errors:
format: ! '%{attribute} %{message}'
general: A problem has occured.
general_again: A problem has occured. Please try again.
general_msg: ! 'A problem has occured: %{msg}'
messages:
accepted: has to be accepted
blank: has to be entered
confirmation: does not match the confirmation
empty: has to be entered
equal_to: has to be exactly %{count}
even: has to be an even number
exclusion: is not available
greater_than: has to be greater than %{count}
greater_than_or_equal_to: has to be greater than or equal to %{count}
inclusion: is not a valid value
invalid: is invalid
less_than: has to be less than %{count}
less_than_or_equal_to: has to be less than or equal to %{count}
not_a_number: is not a number
not_an_integer: must be a whole number
odd: must be odd
record_invalid: ! 'validation failed: %{errors}'
taken: is already taken
taken_with_deleted: is already taken (deleted group)
too_long: is too long (no more than %{count} characters)
too_short: is too short (use more than %{count} characters)
wrong_length: is the wrong length (has to have exactly %{count} characters)
template:
body: ! 'Please check the following fields:'
header:
one: ! 'Could not save %{model}: an error.'
other: ! 'Could not save %{model}: %{count} errors.'
activerecord: activerecord:
attributes: attributes:
article: article:
article_category: article category article_category: Category
availability: Is article available? availability: Is article available?
deposit: deposit availability_short: avail.
fc_price: FC price deposit: Deposit
fc_share: FC share fc_price: FoodCoop price
gross_price: gross price fc_price_short: FC price
price: price fc_share: FoodCoop margin
fc_share_short: FC margin
gross_price: Gross price
manufacturer: Manufacturer
name: Name
note: Note
order_number: Order number
origin: Origin
price: Price (net)
supplier: Supplier
tax: VAT tax: VAT
unit: unit unit: Unit
unit_quantity: unit quantity unit_quantity: Unit quantity
unit_quantity_short: U.Q.
article_category:
description: Description
name: Name
delivery:
delivered_on: Delivery date
note: Note
supplier: Supplier
financial_transaction: financial_transaction:
amount: amount amount: amount
note: note note: note
group_order_article:
ordergroup_id: Ordergroup
result: Amount
invoice:
amount: Amount
date: Billing date
delivery: Delivery
deposit: Deposit charged
deposit_credit: Deposit returned
note: Note
number: Number
order: Order
paid_on: Paid on
supplier: Supplier
message:
body: Body
group_id: Group
private: Private
recipient_tokens: Recipients
sent_to_all: Send to all members
subject: Subject
order:
ends: Ends at
note: Note
starts: Starts at
order_article:
units_to_order: Amount of units
update_current_price: Globally update current price
order_comment:
text: Add comment to this order ...
ordergroup:
contact_address: Address
contact_person: Contact person
contact_phone: Phone
description: Description
ignore_apple_restriction: Ignore order stop by apple points restriction
name: Name
user_tokens: Members
page:
body: Body
parent_id: Parent page
title: Title
stock_article: stock_article:
price: Price price: Price
quantity: Quantity
quantity_available: Available quantity
supplier: Supplier
stock_taking:
date: Date
note: Note
supplier:
address: Address
contact_person: Contact person
customer_number: Customer number
customer_number_short: Cust.nr.
delivery_days: Delivery days
email: Email
fax: Fax
is_subscribed: subscribed?
min_order_quantity: Minimum order quantity
name: Name
note: Note
order_howto: How to order
phone: Phone
phone2: Phone 2
url: Homepage
task:
description: Description
done: Done?
due_date: Due date
duration: Duration
name: Name
required_users: People required
user_list: Responsible user
workgroup: Workgroup
user: user:
email: Email
first_name: First name first_name: First name
last_name: Last name
name: Name
nick: Username
ordergroup: Ordergroup
password: Password password: Password
password_confirmation: Repeat password
phone: Telephone
workgroup:
one: Workgroup
other: Workgroups
workgroup:
description: Description
name: Name
next_weekly_tasks_number: For how many weeks in advance would you like to define tasks?
role_admin: Administration
role_article_meta: Article database
role_finance: Finances
role_orders: Order management
role_suppliers: Suppliers
user_tokens: Members
errors: errors:
format: ! '%{attribute} %{message}'
general: A problem has occured.
general_again: A problem has occured. Please try again.
general_msg: ! 'A problem has occured: %{msg}'
has_many_left: is still associated with a %{collection}! has_many_left: is still associated with a %{collection}!
messages:
accepted: has to be accepted
blank: has to be filled
confirmation: does not match the confirmation
empty: has to be entered
equal_to: has to be exactly %{count}
even: has to be an even number
exclusion: is not available
greater_than: has to be greater than %{count}
greater_than_or_equal_to: has to be greater than or equal to %{count}
inclusion: is not a valid value
invalid: is invalid
less_than: has to be less than %{count}
less_than_or_equal_to: has to be less than or equal to %{count}
not_a_number: is not a number
not_an_integer: must be a whole number
odd: must be odd
record_invalid: ! 'validation failed: %{errors}'
taken: is already taken
taken_with_deleted: is already taken (deleted group)
too_long: is too long (no more than %{count} characters)
too_short: is too short (use more than %{count} characters)
wrong_length: is the wrong length (has to have exactly %{count} characters)
models: models:
task: task:
attributes: attributes:
done: done:
exclusion: finished tasks may not be repeated weekly exclusion: finished tasks may not be repeated weekly
template:
body: ! 'Please check the following fields:'
header:
one: ! 'Could not save %{model}: an error.'
other: ! 'Could not save %{model}: %{count} errors.'
models: models:
article: Article article: Article
article_category: Article category article_category: Article category
@ -212,6 +256,11 @@ en:
workgroups: workgroups:
members: members members: members
name: name name: name
application:
controller:
error_authn: Authentication required!
error_denied: Access denied!
error_members_only: This action is only available to members of the group!
article_categories: article_categories:
create: create:
notice: Category was stored notice: Category was stored
@ -305,20 +354,23 @@ en:
error_nosel: You have selected no articles error_nosel: You have selected no articles
parse_upload: parse_upload:
body: <p><i>Please verify the articles.</i></p> <p><i>Warning, at the moment there is no check for duplicate articles.</i></p> body: <p><i>Please verify the articles.</i></p> <p><i>Warning, at the moment there is no check for duplicate articles.</i></p>
title: Upload articles
sync:
outlist: outlist:
body: ! 'The following articles were outlisted and <b>deleted</b>:' alert_used: Warning, %{article} is used in an open order. Please remove it from the order first.
body: ! 'The following articles were removed from the list and will be <b>deleted</b>:'
body_skip: No articles to delete. body_skip: No articles to delete.
title: Outlist ... title: Remove from list ...
price_short: Price price_short: Price
submit: Delete/update all submit: Synchronize all
title: Synchronize articles with external database title: Synchronize articles with external database
unit_quantity_short: unit quantity unit_quantity_short: Unit quantity
update: update:
body: ! '<p><i>Every article is shown twice. The old values are gray and the text fields contain the current values.</i></p> body: ! 'Every article is shown twice: old values are gray, while the text fields contain updated values. Differences with the old articles are marked yellow.'
<p><i>Differences with the old articles are marked yellow.</i></p>'
title: Update ... title: Update ...
update_msg: ! 'Articles must be updated:' update_msg:
one: One article needs to be updated.
other: ! '%{count} articles need to be updated.'
upload: upload:
body: <p>The file has to be a text file with the ending '.csv' The first line will be ignored when imported</p> <p>The fields have to be separated with semicolons (';') and the text enclosed by double quotation marks ("text...").</p> <p>As character set UTF-8 is demanded. Correct order of the column:</p> body: <p>The file has to be a text file with the ending '.csv' The first line will be ignored when imported</p> <p>The fields have to be separated with semicolons (';') and the text enclosed by double quotation marks ("text...").</p> <p>As character set UTF-8 is demanded. Correct order of the column:</p>
fields: fields:
@ -328,109 +380,13 @@ en:
file_label: Please choose a compatible file file_label: Please choose a compatible file
submit: Upload file submit: Upload file
title: ! '%{supplier} / upload articles' title: ! '%{supplier} / upload articles'
date:
abbr_day_names:
- Su
- Mo
- Tu
- We
- Th
- Fr
- Sa
abbr_month_names:
-
- Jan
- Feb
- Mar
- Apr
- May
- Jun
- Jul
- Aug
- Sep
- Oct
- Nov
- Dec
day_names:
- Sunday
- Monday
- Tuesday
- Wednesday
- Thursday
- Friday
- Saturday
formats:
default: ! '%d/%m/%Y'
long: ! '%e %B %Y'
short: ! '%e %b'
month_names:
-
- January
- February
- March
- April
- May
- June
- July
- August
- September
- October
- November
- December
order:
- :day
- :month
- :year
datetime:
distance_in_words:
about_x_hours:
one: about one hour
other: about %{count} hours
about_x_months:
one: about one month
other: about %{count} months
about_x_years:
one: about one year
other: about %{count} years
almost_x_years:
one: almost one year
other: almost %{count} years
half_a_minute: half a minute
less_than_x_minutes:
one: less than one minute
other: less then %{count} minutes
less_than_x_seconds:
one: less than a second
other: less than %{count} seconds
over_x_years:
one: more then a year
other: more than %{count} year
x_days:
one: one day
other: ! '%{count} days'
x_minutes:
one: one minute
other: ! '%{count} minutes'
x_months:
one: one month
other: ! '%{count} months'
x_seconds:
one: eine Sekunde
other: ! '%{count} seconds'
prompts:
day: day
hour: hours
minute: minutes
month: months
second: seconds
year: years
deliveries: deliveries:
add_stock_change: add_stock_change:
how_many_units: ! 'How many units (%{unit}) to deliver? Stock article name: %{name}.' how_many_units: ! 'How many units (%{unit}) to deliver? Stock article name: %{name}.'
create: create:
notice: Delivery was created. Please dont forget to create invoice! notice: Delivery was created. Please dont forget to create invoice!
create_stock_article: create_stock_article:
notice: The new stock article »%{name}« was saved. notice: The new stock article "%{name}" was saved.
destroy: destroy:
notice: Delivery was deleted. notice: Delivery was deleted.
edit: edit:
@ -478,7 +434,7 @@ en:
update: update:
notice: Delivery was updated. notice: Delivery was updated.
update_stock_article: update_stock_article:
notice: The stock article »%{name}« was updated. notice: The stock article "%{name}" was updated.
documents: documents:
order_by_articles: order_by_articles:
filename: Order %{name}-%{date} - by articles filename: Order %{name}-%{date} - by articles
@ -525,38 +481,9 @@ en:
one: One article in total one: One article in total
other: ! '%{count} articles in total' other: ! '%{count} articles in total'
errors: errors:
format: ! '%{attribute} %{message}'
general: A problem has occured. general: A problem has occured.
general_again: A problem has occured. Please try again. general_again: A problem has occured. Please try again.
general_msg: ! 'A problem has occured: %{msg}' general_msg: ! 'A problem has occured: %{msg}'
messages:
accepted: has to be accepted
blank: has to be filled
confirmation: does not match the confirmation
empty: has to be entered
equal_to: has to be exactly %{count}
even: has to be an even number
exclusion: is not available
greater_than: has to be greater than %{count}
greater_than_or_equal_to: has to be greater than or equal to %{count}
inclusion: is not a valid value
invalid: is invalid
less_than: has to be less than %{count}
less_than_or_equal_to: has to be less than or equal to %{count}
not_a_number: is not a number
not_an_integer: must be a whole number
odd: must be odd
record_invalid: ! 'validation failed: %{errors}'
taken: is already taken
taken_with_deleted: is already taken (deleted group)
too_long: is too long (no more than %{count} characters)
too_short: is too short (use more than %{count} characters)
wrong_length: is the wrong length (has to have exactly %{count} characters)
template:
body: ! 'Please check the following fields:'
header:
one: ! 'Could not save %{model}: an error.'
other: ! 'Could not save %{model}: %{count} errors.'
feedback: feedback:
create: create:
notice: Your feedback was sent successfully. Thanks a lot! notice: Your feedback was sent successfully. Thanks a lot!
@ -648,11 +575,13 @@ en:
create: create:
notice: Invoice was created notice: Invoice was created
financial_transactions: financial_transactions:
create: controller:
notice: The transaction was saved. create:
create_collection: notice: The transaction was saved.
alert: ! 'An error occured: %{error}' create_collection:
notice: All transactions were saved. alert: ! 'An error occured: %{error}'
error_note_required: Note is required!
notice: All transactions were saved.
index: index:
balance: ! 'Balance of account: %{balance}' balance: ! 'Balance of account: %{balance}'
last_updated_at: (last updated %{when} ago) last_updated_at: (last updated %{when} ago)
@ -681,6 +610,7 @@ en:
group_order_articles: group_order_articles:
form: form:
amount_change_for: Change amount for %{article} amount_change_for: Change amount for %{article}
result_hint: ! 'Unit: %{unit}'
index: index:
amount: Amount amount: Amount
amount_fc: Amount(FC) amount_fc: Amount(FC)
@ -716,6 +646,7 @@ en:
title: Invoice %{number} title: Invoice %{number}
order_articles: order_articles:
edit: edit:
stock_alert:
title: Update article title: Update article
new: new:
title: Add delivered article to order title: Add delivered article to order
@ -791,6 +722,8 @@ en:
new_funds: New account balance new_funds: New account balance
note: Note note: Note
price: Price price: Price
reset_article_search: Reset search
search_article: Search for article...
sum: Sum sum: Sum
sum_amount: Current amount sum_amount: Current amount
supplier: Supplier supplier: Supplier
@ -880,15 +813,11 @@ en:
option_choose: Choose supplier/stock option_choose: Choose supplier/stock
option_stock: Stock option_stock: Stock
order_pdf: Create PDF order_pdf: Create PDF
select:
prompt: please select
submit: submit:
create: save %{model}
invite: invite:
create: send invitation create: send invitation
message: message:
create: send message create: send message
update: save changes
tasks: tasks:
required_users: ! '%{count} members are still needed!' required_users: ! '%{count} members are still needed!'
home: home:
@ -899,7 +828,7 @@ en:
warning: Warning, if you have less then %{threshold} of apple points, you are not allowed to place an order! warning: Warning, if you have less then %{threshold} of apple points, you are not allowed to place an order!
changes_saved: Changes saved. changes_saved: Changes saved.
index: index:
due_date_format: ! '%A %d %b' due_date_format: ! '%A %d %B'
messages: messages:
title: Newest Messages title: Newest Messages
view_all: See all messages view_all: See all messages
@ -976,9 +905,11 @@ en:
title: Invite person title: Invite person
new: new:
action: Send invite action: Send invite
back: or go back
body: <p>Here you can add a person to the group <b>%{group}</b>, who is not yet a member of the foodcoop.</p> body: <p>Here you can add a person to the group <b>%{group}</b>, who is not yet a member of the foodcoop.</p>
success: User was invited successfully. success: User was invited successfully.
js:
ordering:
confirm_change: Modifications to this order will be lost when you change the order. Do you want to lose the changes you made and continue?
layouts: layouts:
application1: application1:
title: Foodsoft - %{title} title: Foodsoft - %{title}
@ -1223,57 +1154,6 @@ en:
home: Home home: Home
title: Wiki title: Wiki
workgroups: Workgroups workgroups: Workgroups
number:
currency:
format:
delimiter: .
format: ! '%n %u'
precision: 2
separator: .
significant: false
strip_insignificant_zeros: false
unit:
format:
delimiter: .
precision: 2
separator: ! ','
significant: false
strip_insignificant_zeros: false
human:
decimal_units:
format: ! '%n %u'
units:
billion:
one: billion
other: billions
million: million
quadrillion:
one: quadrillion
other: quadrillions
thousand: thousand
trillion: trillion
unit:
format:
delimiter:
precision: 1
significant: true
strip_insignificant_zeros: true
storage_units:
format: ! '%n %u'
units:
byte:
one: byte
other: bytes
gb: GB
kb: KB
mb: MB
tb: TB
percentage:
format:
delimiter:
precision:
format:
delimiter:
ordergroups: ordergroups:
edit: edit:
title: Edit ordergroups title: Edit ordergroups
@ -1298,7 +1178,6 @@ en:
fax: fax:
amount: Amount amount: Amount
articles: Articles articles: Articles
customer_number: Customer number
delivery_day: Delivery day delivery_day: Delivery day
heading: Order for %{name} heading: Order for %{name}
name: Name name: Name
@ -1314,7 +1193,7 @@ en:
prices: Prices (net/FC) prices: Prices (net/FC)
select_all: Select all select_all: Select all
stockit: In stock stockit: In stock
supplier: Supplier supplier: Producer
title: Article title: Article
unit_quantity: Unit quantity unit_quantity: Unit quantity
index: index:
@ -1396,7 +1275,7 @@ en:
notice: Page was created notice: Page was created
cshow: cshow:
error_noexist: Page doesnt exist! error_noexist: Page doesnt exist!
redirect_notice: Redirected from %{page} .. redirect_notice: Redirected from %{page} ...
destroy: destroy:
notice: The page '%{page}' and all subpages have been deleted successfully. notice: The page '%{page}' and all subpages have been deleted successfully.
edit: edit:
@ -1537,7 +1416,7 @@ en:
message: message:
private: Message doesnt show in Foodsoft mail inbox private: Message doesnt show in Foodsoft mail inbox
order_article: order_article:
units_to_order: Amount of delivered units units_to_order: If you change the total amount of delivered units, you also have to change individual group amounts by clicking on the article name. They will not be automatically recalculated and so ordergroups may be accounted for articles that were not delivered!
update_current_price: Also update the price of the current order update_current_price: Also update the price of the current order
stock_article: stock_article:
copy_stock_article: copy_stock_article:
@ -1552,74 +1431,6 @@ en:
required_users: How many users will be needed in total? required_users: How many users will be needed in total?
tax: In percentage, standard is 7,0 tax: In percentage, standard is 7,0
labels: labels:
article:
article_category: Category
manufacturer: Manufacturer
name: Name
note: Note
origin: Origin
unit: Unit
article_category:
description: Description
name: Name
defaults:
amount: Amount
date: Date
deposit: Deposit
description: Description
email: Email
note: Note
order_number: Order number
ordergroup: Ordergroup
password: Password
password_confirmation: Repeat password
phone: Phone
price: Price (net)
tax: VAT
title: Title
unit_quantity: Unit quantity
user_tokens: Members
delivery:
delivered_on: Delivery date
supplier: Supplier
group_order_article:
ordergroup_id: Ordergroup
result: Amount
invoice:
amount: Amount
date: Billing date
delivery: Delivery
deposit: Deposit charged
deposit_credit: Deposit returned
note: Note
number: Number
order: Order
paid_on: Paid on
supplier: Supplier
message:
body: Body
group_id: Group
private: Private
recipient_tokens: Recipients
sent_to_all: Send to all members
subject: Subject
order:
ends: Ends at
starts: Starts at
order_article:
units_to_order: Amount of units
update_current_price: Globally update current price
order_comment:
text: Add comment to this order ...
ordergroup:
contact_address: Address
contact_person: Contact person
contact_phone: Phone
ignore_apple_restriction: Ignore order stop by apple points restriction
name: Name
page:
body: Body
parent_id: Parent page
settings: settings:
messages: messages:
send_as_email: Receive messages as emails. send_as_email: Receive messages as emails.
@ -1635,48 +1446,6 @@ en:
settings_group: settings_group:
messages: Messages messages: Messages
privacy: Privacy privacy: Privacy
stock_article:
supplier: Supplier
supplier:
address: Address
contact_person: Contact person
customer_number: Customer ID
delivery_days: Delivery days
email: Email
fax: Fax
is_subscribed: subscribed?
min_order_quantity: Minimum order quantity
name: Name
note: Note
order_howto: How to order
phone: Phone
phone2: Phone 2
url: Homepage
task:
done: Done?
due_date: Due date
duration: Duration
name: Name
required_users: People required
user_list: Responsible user
workgroup: Workgroup
user:
email: Email
last_name: Last name
name: Name
nick: Username
ordergroup: Ordergroup
phone: Telephone
workgroup:
one: Workgroup
other: Workgroups
workgroup:
next_weekly_tasks_number: For how many weeks in advance would you like to define tasks?
role_admin: Administration
role_article_meta: Article database
role_finance: Finances
role_orders: Order management
role_suppliers: Suppliers
'no': 'No' 'no': 'No'
options: options:
settings: settings:
@ -1730,15 +1499,6 @@ en:
title: Edit stock articles title: Edit stock articles
form: form:
price_hint: To avoid choas, it is not possible to edit the prices of already added stock articles until further notice. price_hint: To avoid choas, it is not possible to edit the prices of already added stock articles until further notice.
history:
change_quantity: Change
datetime: Time
delivery: Delivery
new_quantity: New quantity
order: Order
reason: Reason
stock_changes: Stock quantity changes of %{article_name}
stock_taking: Inventory
index: index:
article: article:
article: Article article: Article
@ -1764,6 +1524,15 @@ en:
new: new:
search_text: ! 'Search for articles in all catalogues:' search_text: ! 'Search for articles in all catalogues:'
title: Add new stock article title: Add new stock article
show:
change_quantity: Change
datetime: Time
delivery: Delivery
new_quantity: New quantity
order: Order
reason: Reason
stock_changes: Stock quantity changes
stock_taking: Inventory
stock_create: stock_create:
notice: Stock article was created. notice: Stock article was created.
stock_update: stock_update:
@ -1799,11 +1568,6 @@ en:
show_deliveries: Show all deliveries show_deliveries: Show all deliveries
update: update:
notice: Supplier was updated notice: Supplier was updated
support:
array:
last_word_connector: ! ' and '
two_words_connector: ! ' and '
words_connector: ! ', '
tasks: tasks:
accept: accept:
notice: You have accepted the task notice: You have accepted the task
@ -1859,15 +1623,15 @@ en:
show: show:
accept_task: Accept task accept_task: Accept task
confirm_delete_group: Really delete this and all subsequent tasks? confirm_delete_group: Really delete this and all subsequent tasks?
confirm_delete_single: Are you sure you want to delete the task?
delete_group: Delete task and subsequent delete_group: Delete task and subsequent
due_date: Due date
hours: ! '%{count}h' hours: ! '%{count}h'
mark_done: Mark task as done mark_done: Mark task as done
reject_task: Reject task reject_task: Reject task
title: Show task title: Show task
update: update:
notice: Task has been updated notice: Task has been updated
notice_converted: Task has been updated and was converted to a regular task notice_converted: Task has been updated and was converted to a non-repeating task.
user: user:
more: Nothing to do? %{tasks_link} are tasks for sure. more: Nothing to do? %{tasks_link} are tasks for sure.
tasks_link: Here tasks_link: Here
@ -1877,18 +1641,10 @@ en:
workgroup: workgroup:
title: Tasks for %{workgroup} title: Tasks for %{workgroup}
title_all: All group tasks title_all: All group tasks
time:
am: morning
formats:
default: ! '%A, %d %B %Y, %H:%M'
long: ! '%A, %d %B %Y, %H:%M'
short: ! '%d %B, %H:%M'
pm: afternoon
ui: ui:
close: Close close: Close
delete: Delete delete: Delete
edit: Edit edit: Edit
history: Show history
marks: marks:
close: ! '&times;' close: ! '&times;'
success: <i class="icon icon-ok"></i> success: <i class="icon icon-ok"></i>

View file

@ -1,98 +1,142 @@
fr: fr:
activemodel:
errors:
format: ! '%{attribute} %{message}'
general: Un problème a été rencontré.
general_again: Une erreur s'est produite. Merci de réessayer.
general_msg: ! 'Une erreur s''est produite: %{msg}'
messages:
accepted: doit obligatoirement être accepté
blank: doit obligatoirement être complété
confirmation: ne correspond pas avec le champ de confirmation
empty: doit obligatoirement être complété
equal_to: doit obligatoirement être égal à %{count}
even: doit obligatoirement être pair
exclusion: n'est pas disponible
greater_than: doit obligatoirement être supérieur à %{count}
greater_than_or_equal_to: doit obligatoirement être supérieur ou égal à %{count}
inclusion: n'est pas une valeur valide
invalid: n'est pas valide
less_than: doit obligatoirement être inférieur à %{count}
less_than_or_equal_to: doit obligatoirement être inférieur à %{count}
not_a_number: n'est pas un nombre
not_an_integer: doit être un nombre entier
odd: doit obligatoirement être impair
record_invalid: ! 'la vérification a échoué: %{errors}'
taken: a déjà été attribué
taken_with_deleted: a déjà été attribué (à une cellule supprimée depuis)
too_long: est trop long (%{count} signes autorisés au maximum)
too_short: est trop court (%{count} signes au minimum doivent être présents)
wrong_length: n'est pas de la bonne longueur (exactement %{count} signes doivent être présents)
template:
body: ! 'Merci de contrôler le contenu des champs suivants:'
header:
one: ! '%{model} n''a pas pu être sauvegardé à cause de la présence d''une erreur.'
other: ! '%{model} n''a pas pu être sauvegardé car %{count} erreurs ont été trouvées.'
activerecord: activerecord:
attributes: attributes:
article: article:
article_category: catégorie article_category: Catégorie
availability: l'article est-il disponible? availability: l'article est-il disponible?
deposit: consigne availability_short:
fc_price: prix final deposit: Consigne
fc_share: supplément boufcoop fc_price: Prix final
gross_price: prix brut fc_price_short:
price: prix net fc_share: Supplément boufcoop
fc_share_short:
gross_price: Prix brut
manufacturer: ProductRICE_eur
name: Nom
note: Note
order_number: ! 'Numéro '
origin: Lieu de production
price: Prix net
supplier:
tax: TVA tax: TVA
unit: unité unit: Unité
unit_quantity: unités par lot unit_quantity: Unités par lot
unit_quantity_short:
article_category:
description: Description
name: Nom
delivery:
delivered_on: Date de réapprovisionnement
note:
supplier: Fournisseuse_r
financial_transaction: financial_transaction:
amount: montant amount: montant
note: note note: note
group_order_article:
ordergroup_id: Cellul
result: Quantité
invoice:
amount: Montant
date: Date de facturation
delivery: Réapprovisionnement
deposit: Consigne facturée
deposit_credit: Consigne remboursée
note: Note
number: Numéro
order: Commande
paid_on: Payée le
supplier: Fournisseuse_r
message:
body: Contenu
group_id: Cellule ou équipe
private: Privé
recipient_tokens: Destinataires
sent_to_all: Envoyer à tous les membres
subject: Sujet
order:
ends: Clôture le
note:
starts: Ouverture le
order_article:
units_to_order: Quantité
update_current_price: Mettre à jour le prix global
order_comment:
text: Commenter cette commande...
ordergroup:
contact_address: Adresse
contact_person: Personne à contacter
contact_phone: Téléphone
description: Description
ignore_apple_restriction: Pour cette cellule, ne pas bloquer les commandes en cas de manque de glands
name: Nom
user_tokens: Membres
page:
body: Contenu
parent_id: Page parente
title: Titre
stock_article: stock_article:
price: Prix net price: Prix net
quantity:
quantity_available:
supplier: FournisseurE
stock_taking:
date:
note:
supplier:
address: Adresse
contact_person: Contact
customer_number: Numéro de client de la coop
customer_number_short:
delivery_days: Jours de livraison
email: Email
fax: Fa
is_subscribed: abonné?
min_order_quantity: Quantité minimale à commander
name: Nom
note: Note
order_howto: Comment commander
phone: Téléphone
phone2: Autre téléphone
url: Site web
task:
description: Description
done: Fait?
due_date: Echéance
duration: Durée
name: Nom
required_users: Nombre de personnes nécessaires
user_list: Responsables inscritEs
workgroup: Équipe
user: user:
email: Email
first_name: Prénom first_name: Prénom
last_name: Nom de famille
name: Nom
nick: Identifiant
ordergroup: Cellule
password: Mot de passe password: Mot de passe
password_confirmation: Confirmation du mot de passe
phone: Téléphone
workgroup:
one: Équipe
other: Équipes
workgroup:
description: Description
name: Nom
next_weekly_tasks_number: Combien de temps en avance les boulots doivent ils être annoncés sur le site?
role_admin: Administration
role_article_meta: Base de données des articles
role_finance: Trésorerie
role_orders: Gestion des commandes
role_suppliers: Contact avec les fournisseusEs_rs
user_tokens: Membres
errors: errors:
format: ! '%{attribute} %{message}'
general: Une problème a été rencontré.
general_again: Une erreur s'est produite. Merci de réessayer.
general_msg: ! 'Un problème a été rencontré: %{msg}'
has_many_left: est encore associé à une %{collection}! has_many_left: est encore associé à une %{collection}!
messages:
accepted: doit obligatoirement être accepté
blank: doit obligatoirement être complété
confirmation: ne correspond pas au champ de confirmation
empty: doit obligatoirement être complété
equal_to: doit obligatoirement être égal à %{count}
even: doit être un nombre pair
exclusion: n'est pas disponible
greater_than: doit obligatoirement être supérieur à %{count}
greater_than_or_equal_to: doit obligatoirement être supérieur ou égal à %{count}
inclusion: n'est pas un valeur valide
invalid: est invalide
less_than: doit obligatoirement être inférieur à %{count}
less_than_or_equal_to: doit obligatoirement être inférieur ou égal à %{count}
not_a_number: n'est pas un nombre
not_an_integer: doit obligatoirement être un nombre entier
odd: doit obligaroirement être un nombre impair
record_invalid: ! 'la vérification a échoué: %{errors}'
taken: a déjà été attribué
taken_with_deleted: a déjà été attribué (à une cellule supprimée depuis)
too_long: est trop long (au maximum %{count} signes sont autorisés)
too_short: est trop court (au minimum %{count} signes doivent être présents)
wrong_length: n'a pas la bonne longueur (exactement %{count} signes doivent être présents)
models: models:
task: task:
attributes: attributes:
done: done:
exclusion: répétition hebdomadaire invalide pour un boulot déjà effectué exclusion: répétition hebdomadaire invalide pour un boulot déjà effectué
template:
body: ! 'Merci de vérifier le contenu des champs suivants:'
header:
one: ! '%{model} n''a pu être sauvegardé à cause de la présence d''une erreur.'
other: ! '%{model} n''a pu être sauvegardé à cause de %{count} erreurs.'
models: models:
article: Article article: Article
article_category: la nouvelle catégorie article_category: la nouvelle catégorie
@ -212,6 +256,11 @@ fr:
workgroups: workgroups:
members: membres members: membres
name: nom name: nom
application:
controller:
error_authn:
error_denied:
error_members_only:
article_categories: article_categories:
create: create:
notice: La catégorie a bien été définie. notice: La catégorie a bien été définie.
@ -307,7 +356,10 @@ fr:
body: ! '<p><i>Merci de vérifier les articles importés.</i></p> body: ! '<p><i>Merci de vérifier les articles importés.</i></p>
<p><i>Attention, les doublons ne sont pas automatiquement détectés.</p></i>.' <p><i>Attention, les doublons ne sont pas automatiquement détectés.</p></i>.'
title:
sync:
outlist: outlist:
alert_used:
body: ! 'Les articles suivants ne sont plus dans la liste et seront donc <b>supprimés</b>:' body: ! 'Les articles suivants ne sont plus dans la liste et seront donc <b>supprimés</b>:'
body_skip: Aucun article à supprimer. body_skip: Aucun article à supprimer.
title: Exclure de la liste... title: Exclure de la liste...
@ -316,9 +368,9 @@ fr:
title: Synchroniser les articles avec la base de données extérieure title: Synchroniser les articles avec la base de données extérieure
unit_quantity_short: U/L unit_quantity_short: U/L
update: update:
body: <p><i>Chaque article apparaît deux fois. Les anciennes données sont rappelées en gris, et les champs du formulaire ont été préremplis avec les nouvelles valeurs. </i></p><p><i>Les changements sont marqués en jaune.</p></i> body: ! 'Chaque article apparaît deux fois: les anciennes données sont rappelées en gris, et les champs du formulaire ont été préremplis avec les nouvelles valeurs. Les changements sont marqués en jaune.'
title: Mettre à jour... title: Mettre à jour...
update_msg: ! 'Ces articles doivent être mis à jour:' update_msg:
upload: upload:
body: ! '<p>Le fichier doit être au format texte et son nom doit se terminer par l''extension ".csv". La première ligne sera ignorée lors de l''importation.</p> body: ! '<p>Le fichier doit être au format texte et son nom doit se terminer par l''extension ".csv". La première ligne sera ignorée lors de l''importation.</p>
@ -332,102 +384,6 @@ fr:
file_label: Merci de choisir un fichier compatible file_label: Merci de choisir un fichier compatible
submit: Transférer le fichier submit: Transférer le fichier
title: ! '%{supplier} / Transférer les données sur l''article' title: ! '%{supplier} / Transférer les données sur l''article'
date:
abbr_day_names:
- Lun
- Mar
- Mer
- Jeu
- Ven
- Sam
- Dim
abbr_month_names:
-
- Janvier
- Février
- Mars
- Avril
- Mai
- Juin
- Juillet
- Août
- Septembre
- Octobre
- Novembre
- Décembre
day_names:
- Dimanche
- Lundi
- Mardi
- Mercredi
- Jeudi
- Vendredi
- Samedi
formats:
default: ! '%d.%m.%Y'
long: ! '%e.%B %Y'
short: ! '%e. %b'
month_names:
-
- Janvier
- Février
- Mars
- Avril
- Mai
- Juin
- Juillet
- Août
- Septembre
- Octobre
- Novembre
- Décembre
order:
- :day
- :month
- :year
datetime:
distance_in_words:
about_x_hours:
one: environ une heure
other: environ %{count} heures
about_x_months:
one: environ un mois
other: environ %{count} mois
about_x_years:
one: environ un an
other: environ %{count} ans
almost_x_years:
one: presque un an
other: presque %{count} ans
half_a_minute: une demi-minute
less_than_x_minutes:
one: moins d'une minute
other: moins de %{count} minutes
less_than_x_seconds:
one: moins d'une seconde
other: moins de %{count} secondes
over_x_years:
one: plus d'un an
other: plus de %{count} ans
x_days:
one: un jour
other: ! '%{count} jours'
x_minutes:
one: une minute
other: ! '%{count} minutes'
x_months:
one: un mois
other: ! '%{count} mois'
x_seconds:
one: une seconde
other: ! '%{count} secondes'
prompts:
day: jour
hour: heures
minute: minute
month: mois
second: secondes
year: an
deliveries: deliveries:
add_stock_change: add_stock_change:
how_many_units: Combien d unités (%{unit}) de l article %{name} doivent-elles être livrées? how_many_units: Combien d unités (%{unit}) de l article %{name} doivent-elles être livrées?
@ -488,6 +444,7 @@ fr:
filename: Commande %{name}-%{date} - Trier par filename: Commande %{name}-%{date} - Trier par
rows: rows:
- Cellule - Cellule
-
- Quantité - Quantité
- Prix - Prix
title: ! 'Ordre des articles pour la commande: %{name}, close le %{date}' title: ! 'Ordre des articles pour la commande: %{name}, close le %{date}'
@ -495,6 +452,7 @@ fr:
filename: Commande %{name}-%{date} - Répartition par cellules filename: Commande %{name}-%{date} - Répartition par cellules
rows: rows:
- Nom de l'article - Nom de l'article
- Commandée
- Quantité - Quantité
- Prix unitaire - Prix unitaire
- Unités par lot - Unités par lot
@ -510,6 +468,7 @@ fr:
- Nom - Nom
- Nombre de lots - Nombre de lots
- Unité - Unité
- Prix/Unité
- Prix unitaire - Prix unitaire
total: total:
order_matrix: order_matrix:
@ -526,38 +485,9 @@ fr:
one: Un seul article one: Un seul article
other: ! '%{count} articles au total' other: ! '%{count} articles au total'
errors: errors:
format: ! '%{attribute} %{message}'
general: Un problème a été rencontré. general: Un problème a été rencontré.
general_again: Une erreur s'est produite. Merci de réessayer. general_again: Une erreur s'est produite. Merci de réessayer.
general_msg: ! 'Une erreur s''est produite: %{msg}' general_msg: ! 'Une erreur s''est produite: %{msg}'
messages:
accepted: doit obligatoirement être accepté
blank: doit obligatoirement être complété
confirmation: ! ' ne correspond pas au champ de confirmatio'
empty: doit obligatoirement être complété
equal_to: doit obligatoirement être égal à %{count}
even: doit obligatoirement être un nombre pair
exclusion: n'est pas disponible
greater_than: doit obligatoirement être supérieur à %{count}
greater_than_or_equal_to: doit obligatoirement être supérieur ou égal à %{count}
inclusion: n'est pas une valeur valide
invalid: n'est pas valide
less_than: doit obligatoirement être inférieur à %{count}
less_than_or_equal_to: doit obligatoirement être inférieur ou égal à %{count}
not_a_number: n'est pas un nombre
not_an_integer: doit obligatoirement être un nombre entier
odd: doit obligatoirement être un nombre impair
record_invalid: ! 'La vérification a échoué: %{errors}'
taken: a déjà été attribué
taken_with_deleted: a déjà été attribué (à une cellule supprimée depuis)
too_long: est trop long (au maximum %{count} signes sont autorisés)
too_short: est trop court (au minimum %{count} signes doivent être présents)
wrong_length: n'a pas la bonne longueur (exactement %{count} signes doivent être présents)
template:
body: ! 'Merci de contrôler le contenu des champs suivants:'
header:
one: ! '%{model} n''a pas pu être sauvegardé: une erreur trouvée.'
other: ! '%{model} n''a pas pu être sauvegardé: %{count} erreurs trouvées.'
feedback: feedback:
create: create:
notice: Ton commentaire a été transmis avec succès. Merci notice: Ton commentaire a été transmis avec succès. Merci
@ -655,11 +585,13 @@ fr:
create: create:
notice: La facture a bien été définie. notice: La facture a bien été définie.
financial_transactions: financial_transactions:
create: controller:
notice: La transaction a été sauvegardée. create:
create_collection: notice: La transaction a été sauvegardée.
alert: ! 'Une erreur s''est produite: %{error}' create_collection:
notice: Les transactions ont été sauvegardées. alert: ! 'Une erreur s''est produite: %{error}'
error_note_required:
notice: Les transactions ont été sauvegardées.
index: index:
balance: ! 'Solde: %{balance}' balance: ! 'Solde: %{balance}'
last_updated_at: (dernière mise à jour il y a %{when}) last_updated_at: (dernière mise à jour il y a %{when})
@ -688,6 +620,7 @@ fr:
group_order_articles: group_order_articles:
form: form:
amount_change_for: Modification de la quantité de %{article} amount_change_for: Modification de la quantité de %{article}
result_hint:
index: index:
amount: Montant amount: Montant
amount_fc: Montant(boufcoop) amount_fc: Montant(boufcoop)
@ -723,6 +656,7 @@ fr:
title: Facture %{number} title: Facture %{number}
order_articles: order_articles:
edit: edit:
stock_alert:
title: Mettre à jour la liste des article title: Mettre à jour la liste des article
new: new:
title: title:
@ -802,6 +736,8 @@ fr:
new_funds: Nouveau solde new_funds: Nouveau solde
note: Note note: Note
price: Prix price: Prix
reset_article_search:
search_article:
sum: Prix total sum: Prix total
sum_amount: ! 'Quantité déjà commandée:' sum_amount: ! 'Quantité déjà commandée:'
supplier: Fourni par supplier: Fourni par
@ -892,15 +828,11 @@ fr:
option_choose: Choix d'unE fournisseusE_r option_choose: Choix d'unE fournisseusE_r
option_stock: Stock option_stock: Stock
order_pdf: Générer un PDF order_pdf: Générer un PDF
select:
prompt: Faire un choix
submit: submit:
create: Définir %{model}
invite: invite:
create: Envoyer une invitatio create: Envoyer une invitatio
message: message:
create: Envoyer un message create: Envoyer un message
update: Sauvergarder les modifications
tasks: tasks:
required_users: Il manque encore %{count} camarades! required_users: Il manque encore %{count} camarades!
home: home:
@ -994,9 +926,11 @@ fr:
title: Engrainer une personne title: Engrainer une personne
new: new:
action: Engrainer! action: Engrainer!
back: ou revenir en arrière
body: <p>Sur cette page, tu peux engrainer une personne qui ne fait pas encore partie de la Boufcoop à rejoindre la cellule <b>%{group}</b> body: <p>Sur cette page, tu peux engrainer une personne qui ne fait pas encore partie de la Boufcoop à rejoindre la cellule <b>%{group}</b>
success: La_le membre a été engrainéE avec succès! success: La_le membre a été engrainéE avec succès!
js:
ordering:
confirm_change:
layouts: layouts:
application1: application1:
title: Foodsoft - %{title} title: Foodsoft - %{title}
@ -1224,57 +1158,6 @@ fr:
home: Page d'accueil home: Page d'accueil
title: Wiki title: Wiki
workgroups: Équipes workgroups: Équipes
number:
currency:
format:
delimiter: .
format: ! '%n %u'
precision: 2
separator: ! ','
significant: false
strip_insignificant_zeros: false
unit:
format:
delimiter: .
precision: 2
separator: ! ','
significant: false
strip_insignificant_zeros: false
human:
decimal_units:
format: ! '%n %u'
units:
billion:
one: milliard
other: milliards
million: millions
quadrillion:
one: billiard
other: billiards
thousand: mille
trillion: billions
unit:
format:
delimiter:
precision: 1
significant: true
strip_insignificant_zeros: true
storage_units:
format: ! '%n %u'
units:
byte:
one: Octet
other: Octets
gb: Go
kb: kB
mb: MB
tb: TB
percentage:
format:
delimiter:
precision:
format:
delimiter:
ordergroups: ordergroups:
edit: edit:
title: Modifier les cellules title: Modifier les cellules
@ -1288,7 +1171,7 @@ fr:
article_count: ! 'Articles commandés:' article_count: ! 'Articles commandés:'
name: Nom name: Nom
prices: Prix brut/net prices: Prix brut/net
prices_sum: Totaux (des prix bruts/nets) prices_sum: ! 'Totaux (des prix bruts/nets):'
unit_quantity: Unités par lots x Lots unit_quantity: Unités par lots x Lots
units_full: Lots complet units_full: Lots complet
units_ordered: Unités commandées units_ordered: Unités commandées
@ -1299,7 +1182,6 @@ fr:
fax: fax:
amount: Quantité amount: Quantité
articles: Articles articles: Articles
customer_number: Numéro de client de la coop
delivery_day: Jour de livraison delivery_day: Jour de livraison
heading: Commande pour %{name} heading: Commande pour %{name}
name: Nom name: Nom
@ -1536,7 +1418,7 @@ fr:
message: message:
private: Le message n'apparaîtra pas dans la boîte de réception du Foodsoft private: Le message n'apparaîtra pas dans la boîte de réception du Foodsoft
order_article: order_article:
units_to_order: Nombre de lots livrés units_to_order:
update_current_price: Modifie aussi le prix des commandes en cours update_current_price: Modifie aussi le prix des commandes en cours
stock_article: stock_article:
copy_stock_article: copy_stock_article:
@ -1551,74 +1433,6 @@ fr:
required_users: De combien de personnes avons-nous besoin au total? required_users: De combien de personnes avons-nous besoin au total?
tax: En pourcentage, le standard est de 7,0 tax: En pourcentage, le standard est de 7,0
labels: labels:
article:
article_category: Catégorie
manufacturer: ProductRICE_eur
name: Nom
note: Note
origin: Lieu de production
unit: Unité
article_category:
description: Description
name: Nom
defaults:
amount: Montant
date: Date
deposit: Consigne
description: Description
email: Email
note: Note
order_number: ! 'Numéro '
ordergroup: Cellule
password: Mot de passe
password_confirmation: Confirmation du mot de passe
phone: Téléphone
price: Prix (net)
tax: TVA
title: Titre
unit_quantity: Unités par lot
user_tokens: Membres
delivery:
delivered_on: Date de réapprovisionnement
supplier: Fournisseuse_r
group_order_article:
ordergroup_id: Cellul
result: Quantité
invoice:
amount: Montant
date: Date de facturation
delivery: Réapprovisionnement
deposit: Consigne facturée
deposit_credit: Consigne remboursée
note: Note
number: Numéro
order: Commande
paid_on: Payée le
supplier: Fournisseuse_r
message:
body: Contenu
group_id: Cellule ou équipe
private: Privé
recipient_tokens: Destinataires
sent_to_all: Envoyer à tous les membres
subject: Sujet
order:
ends: Clôture le
starts: Ouverture le
order_article:
units_to_order: Quantité
update_current_price: Mettre à jour le prix global
order_comment:
text: Commenter cette commande...
ordergroup:
contact_address: Adresse
contact_person: Personne à contacter
contact_phone: Téléphone
ignore_apple_restriction: Pour cette cellule, ne pas bloquer les commandes en cas de manque de glands
name:
page:
body: Contenu
parent_id: Page parente
settings: settings:
messages: messages:
send_as_email: Transmettre les messages de la boufcoop par email send_as_email: Transmettre les messages de la boufcoop par email
@ -1634,48 +1448,6 @@ fr:
settings_group: settings_group:
messages: Messages messages: Messages
privacy: Confidentialité privacy: Confidentialité
stock_article:
supplier: FournisseurE
supplier:
address: Adresse
contact_person: Contact
customer_number: Numéro de client de la coop
delivery_days: Jours de livraison
email: Email
fax: Fa
is_subscribed: abonné?
min_order_quantity: Quantité minimale à commander
name: Nom
note: Note
order_howto: Comment commander
phone: Téléphone
phone2: Autre téléphone
url: Site web
task:
done: Fait?
due_date: Pour quand?
duration: Durée
name: Nom
required_users: Nombre de personnes nécessaires
user_list: Responsables inscritEs
workgroup: Équipe
user:
email: Email
last_name: Nom de famille
name: Nom
nick: Identifiant
ordergroup: Cellule
phone: Téléphone
workgroup:
one: Équipe
other: Équipes
workgroup:
next_weekly_tasks_number: Combien de temps en avance les boulots doivent ils être annoncés sur le site?
role_admin: Administration
role_article_meta: Base de données des articles
role_finance: Trésorerie
role_orders: Gestion des commandes
role_suppliers: Contact avec les fournisseusEs_rs
'no': Non 'no': Non
options: options:
settings: settings:
@ -1731,15 +1503,6 @@ fr:
title: Modifier l'article title: Modifier l'article
form: form:
price_hint: Pour éviter que ça soit le bazar, les prix des articles en stock ne peuvent plus être modifiés. price_hint: Pour éviter que ça soit le bazar, les prix des articles en stock ne peuvent plus être modifiés.
history:
change_quantity: Modification
datetime: Temps
delivery: Réapprovisionnement
new_quantity: Nouveau stock
order: Commande
reason: Raison
stock_changes: Afficher l'historique pour "%{article_name}"
stock_taking: Inventaire
index: index:
article: article:
article: Article article: Article
@ -1765,6 +1528,15 @@ fr:
new: new:
search_text: ! 'Rechercher des articles dans tous les catalogues:' search_text: ! 'Rechercher des articles dans tous les catalogues:'
title: Ajouter un article au stock title: Ajouter un article au stock
show:
change_quantity: Modification
datetime: Temps
delivery: Réapprovisionnement
new_quantity: Nouveau stock
order: Commande
reason: Raison
stock_changes: Afficher l'historique
stock_taking: Inventaire
stock_create: stock_create:
notice: L'article a été sauvegardé. notice: L'article a été sauvegardé.
stock_update: stock_update:
@ -1804,11 +1576,6 @@ fr:
show_deliveries: Afficher tous les réapprovisionnements show_deliveries: Afficher tous les réapprovisionnements
update: update:
notice: Les données du_de la fournisseurE ont été mises à jour notice: Les données du_de la fournisseurE ont été mises à jour
support:
array:
last_word_connector: et
two_words_connector: et
words_connector: ! ','
tasks: tasks:
accept: accept:
notice: Tu as accepté ce boulot notice: Tu as accepté ce boulot
@ -1868,8 +1635,8 @@ fr:
show: show:
accept_task: Te charger de ce boulot. accept_task: Te charger de ce boulot.
confirm_delete_group: Veux-tu vraiment supprimer ce boulot hebdomadaire? confirm_delete_group: Veux-tu vraiment supprimer ce boulot hebdomadaire?
confirm_delete_single:
delete_group: Supprimer ce boulot delete_group: Supprimer ce boulot
due_date: Echéance
hours: ! '%{count}h' hours: ! '%{count}h'
mark_done: Marquer comme effectué mark_done: Marquer comme effectué
reject_task: Refuser ce boulot reject_task: Refuser ce boulot
@ -1886,18 +1653,10 @@ fr:
workgroup: workgroup:
title: Agenda de l'%{workgroup} title: Agenda de l'%{workgroup}
title_all: Boulot prévu pour l'équipe title_all: Boulot prévu pour l'équipe
time:
am: le matin
formats:
default: ! '%A, %d. %B %Y, %Hh%M'
long: ! '%A, %d. %B %Y, %Hh%M'
short: ! '%d. %B, %Hh%M '
pm: après-midi
ui: ui:
close: Fermer close: Fermer
delete: Supprimer delete: Supprimer
edit: Modifier edit: Modifier
history: Afficher l'historique
marks: marks:
close: ! '&times;' close: ! '&times;'
success: <i class="icon icon-ok"></i> success: <i class="icon icon-ok"></i>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,17 @@
# This file contains overrides that do not go through localeapp.
# If there's a key in one language, it forces presence in other languages
# which means that we can't override in specific languages only. This file
# makes that possible.
en:
number:
currency:
format:
unit: ! '€ '
nl:
number:
currency:
format:
delimiter: ! ' '
unit: ! '€ '
format:
delimiter: ! ' '

View file

@ -97,8 +97,6 @@ Foodsoft::Application.routes.draw do
get :articles_search get :articles_search
get :fill_new_stock_article_form get :fill_new_stock_article_form
end end
get :history
end end
resources :suppliers do resources :suppliers do

View file

@ -20,4 +20,4 @@ Deploy to staging
bundle exec cap deploy bundle exec cap deploy
Deploy to production Deploy to production
bundle exec cap production deploy bundle exec cap production deploy

View file

@ -1,96 +0,0 @@
README for DEVELopment Project Setup
====================================
Gratulations, you have successfully cloned the foodsoft project
from the git repository. Now you are only a few steps away from
trying it out and then jumping into development. (This manual presumes
you have ruby and rails setup.)
(1) Configure datebase
----------------------
Create the database configuration from the default:
cp config/database.yml.SAMPLE config/database.yml
If you are fine with using a file-based sqlite database you are all set.
The sqlite files (development/test/production) will reside in the "db" directory.
Otherwise you would want to edit database.yml to suit your needs (MySQL whatever).
(2) Configure development environment
-------------------------------------
Again, you need to create your own copy of the default configuration:
cp config/environments/development.rb.SAMPLE config/environments/development.rb
Edit development.rb to specify your settings (at least the ActionMailer SMTP settings).
If you just leave the file as is, emails will not work but everything else should be okay.
(3) Foodsoft settings
---------------------
You need to create your own copy of the foodsoft configuration settings:
cp config/app_config.yml.SAMPLE config/app_config.yml
Edit app_config.yml to suit your needs or just keep the defaults for now.
(4) Secret Token
-------------------
The user session are stored in cookies. Do avoid misusing the cookies and its sensitive information, rails
will encrypt it with a token. So copy the config file
cp config/initializers/secret_token.rb.SAMPLE config/initializers/secret_token.rb
and modify the token!!
(5) Required ruby and gems
-------------------
We recommend to use rvm (https://rvm.beginrescueend.com/). Install rvm and get the latest ruby (>= 1.9.3).
If installed you only need to install the gem bundler:
gem install bundler
After that you get the other gems easily with (from project root):
bundle install
(6) Create database (schema) and load defaults
--------------------------
rake db:setup
With this, you also get a ready to go user with username 'admin' and password 'secret'.
(7) Try it out!
---------------
Start the WEBrick server to try it out:
bundle exec rails s
(8) (optional) Get background jobs done
---------------------------------------
We use for time intensive tasks a background job queue, at the moment resque with redis as key/value store.
Install redis (in ubuntu the package redis-server works out of the box) and start the resque worker with:
rake resque:work QUEUE=foodsoft_notifier
To have look on the current queue, failed jobs etc start the resque server with
resque-web
(9) (optional) View mails in browser instead in your logs
---------------------------------------------------------
We use mailcatcher in development mode to view all delivered mails in a browser interface.
Just install mailcatcher with gem install mailcatcher and start the service with
mailcatcher
From now on you have a smpt server listening on 1025. To see the emails go to
http://localhost:1080

View file

@ -3,30 +3,30 @@ Run "rake doc:app" to generate API documentation for your models and controllers
= The Foodsoft = The Foodsoft
is a Web-based software to manage a non-profit food coop (product catalog, ordering, accounting, job scheduling). is a Web-based software to manage a non-profit food coop (product catalog, ordering, accounting, job scheduling).
== Bestellen == Bestellen
Das Bestellen ist der Hauptteil dieser Software und ein wenig kompliziert. Das Bestellen ist der Hauptteil dieser Software und ein wenig kompliziert.
Hier starte ich den Versuch die Programmlogik in Text umzusetzen und Hier starte ich den Versuch die Programmlogik in Text umzusetzen und
verweise auf die enstprechenden Controller bzw. Modelle. verweise auf die enstprechenden Controller bzw. Modelle.
Der relevante Controller ist OrderingController. Der relevante Controller ist OrderingController.
=== Bestellung "in Netz stellen" === Bestellung "in Netz stellen"
Darunter verstehen wir die Auswahl von Artikeln eines bestimmten Lieferanten fuer eine zeitlich begrenzte Darunter verstehen wir die Auswahl von Artikeln eines bestimmten Lieferanten fuer eine zeitlich begrenzte
Bestellung im Internet. Die relevanten Methoden sind OrdersController#newOrder und folgende. Bestellung im Internet. Die relevanten Methoden sind OrdersController#newOrder und folgende.
Jede Bestellung wird durch die Klasse Order abgebildet. Jede Bestellung wird durch die Klasse Order abgebildet.
Die zugehoerigen Artikel werden duch die Klasse OrderArticle mit den Artikeln verknuepft. Die zugehoerigen Artikel werden duch die Klasse OrderArticle mit den Artikeln verknuepft.
Dabei werden auch die Attribute quantity, tolerance und quantity_to_order gespeichert. Dabei werden auch die Attribute quantity, tolerance und quantity_to_order gespeichert.
Diese Mengen repraesentieren die Gesamtbestellung, also alle Bestellgruppen. Diese Mengen repraesentieren die Gesamtbestellung, also alle Bestellgruppen.
=== Eine Bestellgruppe bestellt... === Eine Bestellgruppe bestellt...
Die Methode OrdersController#order schickt uns die Bestellenseite. Mit dieser Oberflaeche Die Methode OrdersController#order schickt uns die Bestellenseite. Mit dieser Oberflaeche
koennen die Bestellgruppena die vorher ausgewaehlten Artikel bestellen. koennen die Bestellgruppena die vorher ausgewaehlten Artikel bestellen.
Mittels den Buttons werden dabei live, also clientseitig, die Preise ermittelt Mittels den Buttons werden dabei live, also clientseitig, die Preise ermittelt
und der Gesamtpreis berechnet. Ist der Gesamtpreis groeßer als der aktuelle und der Gesamtpreis berechnet. Ist der Gesamtpreis groeßer als der aktuelle
Gruppenkontostand, so wird die Preisspalte rot unterlegt und die Bestellung Gruppenkontostand, so wird die Preisspalte rot unterlegt und die Bestellung
kann nicht gespeichert werden. kann nicht gespeichert werden.
=== (gruppen)-Bestellung wird gespeichert === (gruppen)-Bestellung wird gespeichert
@ -67,27 +67,27 @@ Wir unterscheiden dehalb zwei Faelle:
Verringe Bestellung auf 2(1) um 19uhr. Verringe Bestellung auf 2(1) um 19uhr.
=> Zeile mit created_on = 18uhr wird gelöscht und => Zeile mit created_on = 18uhr wird gelöscht und
in der Zeile mit created_on = 17uhr wird der Wert tolerance auf 1 gaendert. in der Zeile mit created_on = 17uhr wird der Wert tolerance auf 1 gaendert.
=== Wer bekommt wieviel? === Wer bekommt wieviel?
Diese Frage wird wie schon erwaehnt mittels der group_order_article_quantites -Tabelle Diese Frage wird wie schon erwaehnt mittels der group_order_article_quantites -Tabelle
geloest. geloest.
Beipspiel. Beipspiel.
articel x mit unit_quantity = 5. articel x mit unit_quantity = 5.
17uhr: gruppe a bestellt 2(3), weil sie auf jeden fall was von x bekommen will 17uhr: gruppe a bestellt 2(3), weil sie auf jeden fall was von x bekommen will
18uhr: gruppe b bestellt 2(0) 18uhr: gruppe b bestellt 2(0)
19uhr: gruppe a faellt ein dass sie doch noch mehr braucht von x und aendert auf 4(1). 19uhr: gruppe a faellt ein dass sie doch noch mehr braucht von x und aendert auf 4(1).
jetzt gibt es drei zeilen in der tabelle, die so aussehen: jetzt gibt es drei zeilen in der tabelle, die so aussehen:
(gruppe a), 2(1), 17uhr (wurde um 19uhr von 2(3) auf 2(1) geaendert) (gruppe a), 2(1), 17uhr (wurde um 19uhr von 2(3) auf 2(1) geaendert)
(gruppe b), 2(0), 18uhr (gruppe b), 2(0), 18uhr
(gruppe a), 2(0), 19uhr. (gruppe a), 2(0), 19uhr.
die zuteilung wird dann wie folgt ermittelt: die zuteilung wird dann wie folgt ermittelt:
zeile 1: gruppe a bekommt 2 zeile 1: gruppe a bekommt 2
zeile 2: gruppe b bekommt 2 zeile 2: gruppe b bekommt 2
zeile 3: gruppe a bekommt 1, weil jetzt das gebinde schon voll ist. zeile 3: gruppe a bekommt 1, weil jetzt das gebinde schon voll ist.
Endstand: insg. Bestellt wurden 6(1) Endstand: insg. Bestellt wurden 6(1)
Gruppe a bekommt 3 einheiten. Gruppe a bekommt 3 einheiten.
gruppe b bekommt 2 einheiten. gruppe b bekommt 2 einheiten.

147
doc/SETUP_DEVELOPMENT.md Normal file
View file

@ -0,0 +1,147 @@
Getting foodsoft running for development
========================================
Gratulations, if you read this file locally, you have successfully cloned the
foodsoft project from the git repository. Now you are only a few steps away
from trying it out and then jumping into development.
**System requirements**:
[RVM](https://rvm.io/rvm/install),
[Ruby 1.9.3](https://www.ruby-lang.org/en/downloads/) and
[Bundler](http://bundler.io/).
Getting started
---------------
0. Clone the repository from GitHub:
```
git clone https://github.com/foodcoops/foodsoft.git
```
1. Install RVM and Ruby 1.9.3 (if you have not done so before):
```
\curl -L https://get.rvm.io | bash
source ~/.rvm/scripts/rvm
rvm install 1.9.3
```
2. Install Ruby dependencies:
```
bundle install
```
3. Setup your development environment:
```
rake foodsoft:setup_development
```
This will interactively prompt with several questions relating to your
required environment.
4. Start rails by running:
```
bundle exec rails s
```
5. Open your favorite browser and open the web application at:
```
http://localhost:3000/
```
You might want to watch a
[kitten video](https://www.youtube.com/watch?v=9Iq5yCoHp4o)
while it's loading.
6. Login using the default credentials: `admin/secret`
7. Change the admin password, just in case.
8. Have phun!
Manual configuration
--------------------
The rake task `foodsoft:setup_development` helps you to setup foodsoft.
If you want to have more control, you can do these steps manually as
explained here.
1. **Configure datebase**
Create the database configuration from the default:
```sh
cp config/database.yml.SQLite_SAMPLE config/database.yml
```
If you are fine with using a file-based sqlite database you are all set.
The sqlite files (development/test/production) will reside in the "db"
directory. Otherwise you would want to copy one of the other
"database.yml.*_SAMPLE" files and edit database.yml to suit your needs.
2. **Configure development environment**
Again, you need to create your own copy of the default configuration:
```
cp config/environments/development.rb.SAMPLE config/environments/development.rb
```
Edit development.rb to specify your settings (at least the ActionMailer SMTP
settings). If you just leave the file as is, emails will not work but
everything else should be okay.
3. **Foodsoft settings**
You need to create your own copy of the foodsoft configuration settings:
```
cp config/app_config.yml.SAMPLE config/app_config.yml
```
Edit app_config.yml to suit your needs or just keep the defaults for now.
4. **Secret token**
The user session are stored in cookies. Do avoid misusing the cookies and
its sensitive information, rails will encrypt it with a token. So copy the
config file
```
cp config/initializers/secret_token.rb.SAMPLE config/initializers/secret_token.rb
```
and modify the token!! You can run `bundle exec rake secret`
5. **Create database (schema) and load defaults**
```
rake db:setup
```
With this, you also get a ready to go user with username 'admin' and
password 'secret'.
6. (optional) Get **background jobs** done
We use for time intensive tasks a background job queue, at the moment resque
with redis as key/value store. Install redis (in ubuntu the package
redis-server works out of the box) and start the resque worker with:
```
rake resque:work QUEUE=foodsoft_notifier
```
To have look on the current queue, failed jobs etc start the resque server with
```
resque-web
```
7. (optional) **View mails in browser** instead in your logs
We use mailcatcher in development mode to view all delivered mails in a
browser interface. Just install mailcatcher with gem install mailcatcher
and start the service with
```
mailcatcher
```
From now on you have a smtp server listening on 1025. To see the emails go to
```
http://localhost:1080
```

11
doc/SETUP_PRODUCTION.md Normal file
View file

@ -0,0 +1,11 @@
Running foodsoft in production
==============================
As you might have noticed, documentation is scarce and insufficient. If you
intend to deploy foodsoft in production, we would love to guide you through the
process. You can contact the mailing list
[foodsoft-discuss](http://foodsoft.51229.x6.nabble.com/foodsoft-discuss-f5.html),
or mail some of us directly at
[developers@foodcoop.nl](mailto:developers@foodcoop.nl) or foodsoft (at)
foodcoops.net.

View file

@ -5,12 +5,12 @@ namespace :foodsoft do
task :notify_upcoming_tasks => :environment do task :notify_upcoming_tasks => :environment do
tasks = Task.where(done: false, due_date: 1.day.from_now.to_date) tasks = Task.where(done: false, due_date: 1.day.from_now.to_date)
for task in tasks for task in tasks
puts "Send notifications for #{task.name} to .." rake_say "Send notifications for #{task.name} to .."
for user in task.users for user in task.users
begin begin
Mailer.upcoming_tasks(user, task).deliver if user.settings.notify['upcoming_tasks'] == 1 Mailer.upcoming_tasks(user, task).deliver if user.settings.notify['upcoming_tasks'] == 1
rescue rescue
puts "deliver aborted for #{user.email}.." rake_say "deliver aborted for #{user.email}.."
end end
end end
end end
@ -27,7 +27,7 @@ namespace :foodsoft do
begin begin
Mailer.not_enough_users_assigned(task, user).deliver Mailer.not_enough_users_assigned(task, user).deliver
rescue rescue
puts "deliver aborted for #{user.email}" rake_say "deliver aborted for #{user.email}"
end end
end end
end end
@ -47,3 +47,8 @@ namespace :foodsoft do
end end
end end
end end
# Helper
def rake_say(message)
puts message unless Rake.application.options.silent
end

View file

@ -8,7 +8,7 @@ namespace :multicoops do
task :run => :environment do task :run => :environment do
task_to_run = ENV['TASK'] task_to_run = ENV['TASK']
FoodsoftConfig.each_coop do |coop| FoodsoftConfig.each_coop do |coop|
puts "Run '#{task_to_run}' for #{coop}" rake_say "Run '#{task_to_run}' for #{coop}"
Rake::Task[task_to_run].execute Rake::Task[task_to_run].execute
end end
end end
@ -17,8 +17,14 @@ namespace :multicoops do
task :run_single => :environment do task :run_single => :environment do
task_to_run = ENV['TASK'] task_to_run = ENV['TASK']
FoodsoftConfig.select_foodcoop ENV['FOODCOOP'] FoodsoftConfig.select_foodcoop ENV['FOODCOOP']
puts "Run '#{task_to_run}' for #{ENV['FOODCOOP']}" rake_say "Run '#{task_to_run}' for #{ENV['FOODCOOP']}"
Rake::Task[task_to_run].execute Rake::Task[task_to_run].execute
end end
end end
# Helper
def rake_say(message)
puts message unless Rake.application.options.silent
end

View file

@ -1,40 +0,0 @@
# General Apache options
AddHandler fastcgi-script .fcgi
AddHandler cgi-script .cgi
Options +FollowSymLinks +ExecCGI
# If you don't want Rails to look in certain directories,
# use the following rewrite rules so that Apache won't rewrite certain requests
#
# Example:
# RewriteCond %{REQUEST_URI} ^/notrails.*
# RewriteRule .* - [L]
# Redirect all requests not available on the filesystem to Rails
# By default the cgi dispatcher is used which is very slow
#
# For better performance replace the dispatcher with the fastcgi one
#
# Example:
# RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
RewriteEngine On
# If your Rails application is accessed via an Alias directive,
# then you MUST also set the RewriteBase in this htaccess file.
#
# Example:
# Alias /myrailsapp /path/to/myrailsapp/public
# RewriteBase /myrailsapp
RewriteRule ^$ index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ dispatch.cgi [QSA,L]
# In case Rails experiences terminal errors
# Instead of displaying this message you can supply a file here which will be rendered instead
#
# Example:
# ErrorDocument 500 /500.html
ErrorDocument 500 "<h2>Application error</h2>Rails application failed to start properly"

View file

@ -1,277 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<title>Ruby on Rails: Welcome aboard</title>
<style type="text/css" media="screen">
body {
margin: 0;
margin-bottom: 25px;
padding: 0;
background-color: #f0f0f0;
font-family: "Lucida Grande", "Bitstream Vera Sans", "Verdana";
font-size: 13px;
color: #333;
}
h1 {
font-size: 28px;
color: #000;
}
a {color: #03c}
a:hover {
background-color: #03c;
color: white;
text-decoration: none;
}
#page {
background-color: #f0f0f0;
width: 750px;
margin: 0;
margin-left: auto;
margin-right: auto;
}
#content {
float: left;
background-color: white;
border: 3px solid #aaa;
border-top: none;
padding: 25px;
width: 500px;
}
#sidebar {
float: right;
width: 175px;
}
#footer {
clear: both;
}
#header, #about, #getting-started {
padding-left: 75px;
padding-right: 30px;
}
#header {
background-image: url("images/rails.png");
background-repeat: no-repeat;
background-position: top left;
height: 64px;
}
#header h1, #header h2 {margin: 0}
#header h2 {
color: #888;
font-weight: normal;
font-size: 16px;
}
#about h3 {
margin: 0;
margin-bottom: 10px;
font-size: 14px;
}
#about-content {
background-color: #ffd;
border: 1px solid #fc0;
margin-left: -11px;
}
#about-content table {
margin-top: 10px;
margin-bottom: 10px;
font-size: 11px;
border-collapse: collapse;
}
#about-content td {
padding: 10px;
padding-top: 3px;
padding-bottom: 3px;
}
#about-content td.name {color: #555}
#about-content td.value {color: #000}
#about-content.failure {
background-color: #fcc;
border: 1px solid #f00;
}
#about-content.failure p {
margin: 0;
padding: 10px;
}
#getting-started {
border-top: 1px solid #ccc;
margin-top: 25px;
padding-top: 15px;
}
#getting-started h1 {
margin: 0;
font-size: 20px;
}
#getting-started h2 {
margin: 0;
font-size: 14px;
font-weight: normal;
color: #333;
margin-bottom: 25px;
}
#getting-started ol {
margin-left: 0;
padding-left: 0;
}
#getting-started li {
font-size: 18px;
color: #888;
margin-bottom: 25px;
}
#getting-started li h2 {
margin: 0;
font-weight: normal;
font-size: 18px;
color: #333;
}
#getting-started li p {
color: #555;
font-size: 13px;
}
#search {
margin: 0;
padding-top: 10px;
padding-bottom: 10px;
font-size: 11px;
}
#search input {
font-size: 11px;
margin: 2px;
}
#search-text {width: 170px}
#sidebar ul {
margin-left: 0;
padding-left: 0;
}
#sidebar ul h3 {
margin-top: 25px;
font-size: 16px;
padding-bottom: 10px;
border-bottom: 1px solid #ccc;
}
#sidebar li {
list-style-type: none;
}
#sidebar ul.links li {
margin-bottom: 5px;
}
</style>
<script type="text/javascript" src="javascripts/prototype.js"></script>
<script type="text/javascript" src="javascripts/effects.js"></script>
<script type="text/javascript">
function about() {
if (Element.empty('about-content')) {
new Ajax.Updater('about-content', 'rails/info/properties', {
method: 'get',
onFailure: function() {Element.classNames('about-content').add('failure')},
onComplete: function() {new Effect.BlindDown('about-content', {duration: 0.25})}
});
} else {
new Effect[Element.visible('about-content') ?
'BlindUp' : 'BlindDown']('about-content', {duration: 0.25});
}
}
window.onload = function() {
$('search-text').value = '';
$('search').onsubmit = function() {
$('search-text').value = 'site:rubyonrails.org ' + $F('search-text');
}
}
</script>
</head>
<body>
<div id="page">
<div id="sidebar">
<ul id="sidebar-items">
<li>
<form id="search" action="http://www.google.com/search" method="get">
<input type="hidden" name="hl" value="en" />
<input type="text" id="search-text" name="q" value="site:rubyonrails.org " />
<input type="submit" value="Search" /> the Rails site
</form>
</li>
<li>
<h3>Join the community</h3>
<ul class="links">
<li><a href="http://www.rubyonrails.org/">Ruby on Rails</a></li>
<li><a href="http://weblog.rubyonrails.org/">Official weblog</a></li>
<li><a href="http://lists.rubyonrails.org/">Mailing lists</a></li>
<li><a href="http://wiki.rubyonrails.org/rails/pages/IRC">IRC channel</a></li>
<li><a href="http://wiki.rubyonrails.org/">Wiki</a></li>
<li><a href="http://dev.rubyonrails.org/">Bug tracker</a></li>
</ul>
</li>
<li>
<h3>Browse the documentation</h3>
<ul class="links">
<li><a href="http://api.rubyonrails.org/">Rails API</a></li>
<li><a href="http://stdlib.rubyonrails.org/">Ruby standard library</a></li>
<li><a href="http://corelib.rubyonrails.org/">Ruby core</a></li>
</ul>
</li>
</ul>
</div>
<div id="content">
<div id="header">
<h1>Welcome aboard</h1>
<h2>You&rsquo;re riding the Rails!</h2>
</div>
<div id="about">
<h3><a href="rails/info/properties" onclick="about(); return false">About your application&rsquo;s environment</a></h3>
<div id="about-content" style="display: none"></div>
</div>
<div id="getting-started">
<h1>Getting started</h1>
<h2>Here&rsquo;s how to get rolling:</h2>
<ol>
<li>
<h2>Create your databases and edit <tt>config/database.yml</tt></h2>
<p>Rails needs to know your login and password.</p>
</li>
<li>
<h2>Use <tt>script/generate</tt> to create your models and controllers</h2>
<p>To see all available options, run it without parameters.</p>
</li>
<li>
<h2>Set up a default route and remove or rename this file</h2>
<p>Routes are setup in config/routes.rb.</p>
</li>
</ol>
</div>
</div>
<div id="footer">&nbsp;</div>
</div>
</body>
</html>

View file

@ -1,10 +0,0 @@
#!/usr/bin/ruby1.8
require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
# If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like:
# "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired
require "dispatcher"
ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) } if defined?(Apache::RubyRun)
Dispatcher.dispatch

View file

@ -1,26 +0,0 @@
#!/usr/bin/ruby1.8
#
# You may specify the path to the FastCGI crash log (a log of unhandled
# exceptions which forced the FastCGI instance to exit, great for debugging)
# and the number of requests to process before running garbage collection.
#
# By default, the FastCGI crash log is RAILS_ROOT/log/fastcgi.crash.log
# and the GC period is nil (turned off). A reasonable number of requests
# could range from 10-100 depending on the memory footprint of your app.
#
# Example:
# # Default log path, normal GC behavior.
# RailsFCGIHandler.process!
#
# # Default log path, 50 requests between GC.
# RailsFCGIHandler.process! nil, 50
#
# # Custom log path, normal GC behavior.
# RailsFCGIHandler.process! '/var/log/myapp_fcgi_crash.log'
#
RAILS_ENV = "production"
require File.dirname(__FILE__) + "/../config/environment"
require 'fcgi_handler'
RailsFCGIHandler.process!

View file

@ -1,10 +0,0 @@
#!/usr/bin/ruby1.8
require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
# If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like:
# "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired
require "dispatcher"
ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) } if defined?(Apache::RubyRun)
Dispatcher.dispatch

View file

@ -38,6 +38,8 @@ if ! heroku apps | grep -q "^$APP\s"; then
heroku create "$APP" --region "$REGION" heroku create "$APP" --region "$REGION"
heroku addons:add heroku-postgresql:dev --app "$APP" heroku addons:add heroku-postgresql:dev --app "$APP"
heroku pg:promote `heroku config | grep 'HEROKU_POSTGRESQL_.*_URL' | cut -d: -f1` heroku pg:promote `heroku config | grep 'HEROKU_POSTGRESQL_.*_URL' | cut -d: -f1`
# user-env-compile needed because config.assets.initialize_on_precompile is true
heroku labs:enable user-env-compile --app "$APP"
fi fi
heroku config:set RACK_ENV="${RAILS_ENV}" RAILS_ENV="${RAILS_ENV}" --app "$APP" heroku config:set RACK_ENV="${RAILS_ENV}" RAILS_ENV="${RAILS_ENV}" --app "$APP"
@ -66,7 +68,7 @@ echo 'web: bundle exec unicorn -p $PORT -E $RACK_ENV' >Procfile
sed -i 's|\(#\s*\)\?\(config\.action_mailer\.raise_delivery_errors\)\s*=.*|\2 = false|' config/environments/${RAILS_ENV}.rb sed -i 's|\(#\s*\)\?\(config\.action_mailer\.raise_delivery_errors\)\s*=.*|\2 = false|' config/environments/${RAILS_ENV}.rb
sed -i 's|\(#\s*\)\?\(config\.action_mailer\.delivery_method\)\s*=.*|\2 = :smtp|' config/environments/${RAILS_ENV}.rb sed -i 's|\(#\s*\)\?\(config\.action_mailer\.delivery_method\)\s*=.*|\2 = :smtp|' config/environments/${RAILS_ENV}.rb
# do not ignore deployment files # do not ignore deployment files
sed -i 's|^\(config/\*.yml\)|#\1|' .gitignore sed -i 's|^\(config/.*\.yml\)|#\1|' .gitignore
sed -i 's|^\(config/initializers/secret_token.rb\)|#\1|' .gitignore sed -i 's|^\(config/initializers/secret_token.rb\)|#\1|' .gitignore
sed -i 's|^\(config/environments/development.rb\)|#\1|' .gitignore sed -i 's|^\(config/environments/development.rb\)|#\1|' .gitignore
# make sure we have a full configuration # make sure we have a full configuration
@ -85,6 +87,8 @@ else
Foodsoft::Application.config.secret_token = '`openssl rand -hex 128`' Foodsoft::Application.config.secret_token = '`openssl rand -hex 128`'
EOF EOF
fi fi
# update Gemfile.lock after Gemfile updates (required by heroku)
bundle install --quiet
# configure localeapp, manually to include environment # configure localeapp, manually to include environment
if [ "$LOCALEAPP_KEY" ]; then if [ "$LOCALEAPP_KEY" ]; then
cat >config/initializers/localeapp.rb <<EOF cat >config/initializers/localeapp.rb <<EOF
@ -100,9 +104,8 @@ EOF
gem 'localeapp'" >>Gemfile gem 'localeapp'" >>Gemfile
# also do not cache so we get locale updates # also do not cache so we get locale updates
sed -i 's|\(#\s*\)\?\(config\.cache_classes\)\s*=.*|\2 = false|' config/environments/${RAILS_ENV}.rb sed -i 's|\(#\s*\)\?\(config\.cache_classes\)\s*=.*|\2 = false|' config/environments/${RAILS_ENV}.rb
bundle exec localeapp pull
fi fi
# update Gemfile.lock after Gemfile updates (required by heroku)
bundle install --quiet
# TODO add more extensive database seed # TODO add more extensive database seed
# and push = deploy # and push = deploy
@ -115,11 +118,9 @@ if !heroku run rake db:version >/dev/null 2>&1; then
else else
heroku run rake db:migrate heroku run rake db:migrate
fi fi
# get full translations so update works
[ "$LOCALEAPP_KEY" ] && heroku run localeapp pull
# restart just to be sure # restart just to be sure
heroku ps:restart #heroku ps:restart
# return to original branch # return to original branch
git checkout -q "$ORIG_BRANCH" && git stash pop -q git checkout -q "$ORIG_BRANCH" && git stash pop -q

View file

@ -1,7 +1,7 @@
require 'spec_helper' require 'spec_helper'
require 'i18n-spec' require 'i18n-spec'
Dir.glob('config/locales/*.yml').each do |locale_file| Dir.glob('config/locales/??{-*,}.yml').each do |locale_file|
describe "#{locale_file}" do describe "#{locale_file}" do
it_behaves_like 'a valid locale file', locale_file it_behaves_like 'a valid locale file', locale_file
# We're currently allowing both German and English as source language # We're currently allowing both German and English as source language

View file

@ -103,6 +103,23 @@ describe 'settling an order', :type => :feature do
expect(GroupOrderArticle.exists?(goa1.id)).to be_false expect(GroupOrderArticle.exists?(goa1.id)).to be_false
end end
it 'keeps product when amount is set to zero' do
within("#order_article_#{oa.id}") do
click_link I18n.t('ui.edit')
end
within("#edit_order_article_#{oa.id}") do
fill_in :order_article_units_to_order, :with => 0
find('input[type="submit"]').click
end
expect(page).to have_selector("#order_article_#{oa.id}")
# make sure it still works after reloading
visit new_finance_order_path(order_id: order.id)
expect(page).to have_selector("#order_article_#{oa.id}")
expect(OrderArticle.exists?(oa.id)).to be_true
oa.reload
expect(oa.units_to_order).to eq(0)
end
end end
end end