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
tmp/**/*
config/*.yml
config/app_config.yml
config/database.yml
config/initializers/secret_token.rb
db/*.sqlite3
nbproject/
@ -16,4 +17,4 @@ doc/app/
Capfile
config/deploy.rb
config/deploy/*
.localeapp
.localeapp

14
Gemfile
View File

@ -9,24 +9,26 @@ gem "rails", '~> 3.2.9'
group :assets do
gem 'sass-rails', '~> 3.2.3'
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
gem 'therubyracer', platforms: :ruby
gem 'uglifier', '>= 1.0.3'
end
gem 'jquery-rails'
gem 'select2-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 'prawn'
gem 'haml-rails'
gem 'kaminari'
gem 'client_side_validations'
gem 'simple_form'
gem 'client_side_validations'
gem 'client_side_validations-simple_form'
gem 'inherited_resources'
gem 'localize_input', git: "git://github.com/bennibu/localize_input.git"
gem 'wikicloth'
@ -42,7 +44,7 @@ gem 'resque'
gem 'whenever', require: false # For defining cronjobs, see config/schedule.rb
group :production do
gem 'exception_notification', require: 'exception_notifier'
gem 'exception_notification'
end
group :development do

View File

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

View File

@ -3,16 +3,30 @@ 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)
[![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).
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).
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
-------

View File

@ -1,5 +1,4 @@
//= require jquery
//= require jquery-ui
//= require jquery_ujs
//= require select2
//= require twitter/bootstrap
@ -7,8 +6,16 @@
//= require bootstrap-datepicker/core
//= require bootstrap-datepicker/locales/bootstrap-datepicker.de
//= require bootstrap-datepicker/locales/bootstrap-datepicker.nl
//= require bootstrap-datepicker/locales/bootstrap-datepicker.fr
//= require jquery.observe_field
//= require list
//= require list.unlist
//= require list.delay
//= require list.reset
//= require rails.validations
//= require rails.validations.simple_form
//= require i18n
//= require i18n/translations
//= require_self
//= require ordering
//= require stupidtable
@ -30,19 +37,19 @@ $.fn.extend({
$(function() {
// 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();
return false;
});
// 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();
return false;
});
// Check/Uncheck a single checkbox
$('[data-check-this]').live('click', function() {
$(document).on('click', '[data-check-this]', function() {
var checkbox = $($(this).data('check-this'));
checkbox.attr('checked', !checkbox.is(':checked'));
highlightRow(checkbox);
@ -50,7 +57,7 @@ $(function() {
});
// 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 context = $(this).data('check-all');
var elms = $('input[type="checkbox"]', context);
@ -62,7 +69,7 @@ $(function() {
});
// 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');
if (confirmMessage) {
if (confirm(confirmMessage)) {
@ -95,7 +102,7 @@ $(function() {
});
// Remote paginations
$('div.pagination[data-remote] a').live('click', function() {
$(document).on('click', 'div.pagination[data-remote] a', function() {
$.getScript($(this).attr('href'));
return false;
});
@ -116,6 +123,20 @@ $(function() {
// Use bootstrap datepicker for dateinput
$('.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
});
@ -142,3 +163,5 @@ function highlightRow(checkbox) {
function setHiddenId(text, li) {
$('hidden_id').value = li.id;
}

View File

@ -1,4 +1,3 @@
jQuery ->
$("a[rel=popover]").popover()
$(".tooltip").tooltip()
$("a[rel=tooltip]").tooltip()
$("a[rel~=popover], .has-popover").popover()
$("a[rel~=tooltip], .has-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 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 toleranceIsCostly = true; // default tolerance behaviour
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 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) {
toleranceIsCostly = value;
}
@ -124,7 +115,7 @@ function update(item, quantity, tolerance) {
} else {
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
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();
}
function asMoney(amount) {
return String(amount.toFixed(currencyPrecision)).replace(/\./, currencySeparator) + ' ' + currencyUnit;
}
function calcUnits(unitSize, quantity, tolerance) {
var units = Math.floor(quantity / unitSize)
var remainder = quantity % unitSize
@ -158,10 +145,10 @@ function updateBalance() {
for (i in itemTotal) {
total += itemTotal[i];
}
$('#total_price').html(asMoney(total));
$('#total_price').html(I18n.l("currency", total));
var balance = groupBalance - total;
$('#new_balance').html(asMoney(balance));
$('#total_balance').val(asMoney(balance));
$('#new_balance').html(I18n.l("currency", balance));
$('#total_balance').val(I18n.l("currency", balance));
// determine bgcolor and submit button state according to balance
var bgcolor = '';
if (balance < minimumBalance) {
@ -191,6 +178,6 @@ $(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 token-input-bootstrappy
*= require bootstrap-datepicker
*= require list.unlist
*/

View File

@ -1,24 +1,23 @@
@import "twitter/bootstrap/bootstrap";
@import "twitter/bootstrap/responsive";
body {
padding-top: 10px;
}
@import "twitter/bootstrap/responsive";
// Set the correct sprite paths
@iconSpritePath: asset-path('twitter/bootstrap/glyphicons-halflings.png');
@iconWhiteSpritePath: asset-path('twitter/bootstrap/glyphicons-halflings-white.png');
@iconSpritePath: image-url('twitter/bootstrap/glyphicons-halflings.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)
// Note: If you use asset_path() here, your compiled boostrap_and_overrides.css will not
// have the proper paths. So for now we use the absolute path.
@fontAwesomeEotPath: '/assets/fontawesome-webfont.eot';
@fontAwesomeWoffPath: '/assets/fontawesome-webfont.woff';
@fontAwesomeTtfPath: '/assets/fontawesome-webfont.ttf';
@fontAwesomeSvgPath: '/assets/fontawesome-webfont.svg';
@fontAwesomeEotPath: asset-url('fontawesome-webfont.eot');
@fontAwesomeEotPath_iefix: asset-url('fontawesome-webfont.eot?#iefix');
@fontAwesomeWoffPath: asset-url('fontawesome-webfont.woff');
@fontAwesomeTtfPath: asset-url('fontawesome-webfont.ttf');
@fontAwesomeSvgPath: asset-url('fontawesome-webfont.svg#fontawesomeregular');
@import 'fontawesome/font-awesome';
// Font Awesome
@import "fontawesome";
// Glyphicons
//@import "twitter/bootstrap/sprites.less";
// Your custom LESS stylesheets goes here
//
@ -26,7 +25,7 @@ body {
// you may use and inherit here
//
// 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:
// @linkColor: #ff0000;
@ -238,3 +237,8 @@ tr.unavailable {
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
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
private
@ -37,7 +37,7 @@ class ApplicationController < ActionController::Base
# No user at all: redirect to login page.
session[:user_id] = nil
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
# We have an authenticated user, now check role...
# Roles gets the user through his memberships.
@ -83,7 +83,7 @@ class ApplicationController < ActionController::Base
def authenticate_membership_or_admin
@group = Group.find(params[:id])
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

View File

@ -7,12 +7,12 @@ class ArticlesController < ApplicationController
sort = case params['sort']
when "name" then "articles.name"
when "unit" then "articles.unit"
when "category" then "article_categories.name"
when "article_category" then "article_categories.name"
when "note" then "articles.note"
when "availability" then "articles.availability"
when "name_reverse" then "articles.name 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 "availability_reverse" then "articles.availability DESC"
end

View File

@ -10,7 +10,7 @@ class Finance::BalancingController < Finance::BaseController
flash.now.alert = t('finance.balancing.new.alert') if @order.closed?
@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})
sort_param = params['sort'] || 'name'

View File

@ -34,7 +34,7 @@ class Finance::FinancialTransactionsController < ApplicationController
@financial_transaction = FinancialTransaction.new(params[:financial_transaction])
@financial_transaction.user = current_user
@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
flash.now[:alert] = error.message
render :action => :new
@ -44,16 +44,16 @@ class Finance::FinancialTransactionsController < ApplicationController
end
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|
# ignore empty amount fields ...
unless trans[:amount].blank?
Ordergroup.find(trans[:ordergroup_id]).add_financial_transaction!(trans[:amount], params[:note], @current_user)
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
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
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".
def reset_password
if request.get? || params[:user].nil? # Catch for get request and give better error message.
redirect_to forgot_password_url, alert: 'Ein Problem ist aufgetreten. Bitte erneut versuchen' and return
redirect_to forgot_password_url, alert: I18n.t('errors.general_again') and return
end
if (user = User.find_by_email(params[:user][:email]))

View File

@ -98,6 +98,8 @@ class OrdersController < ApplicationController
order = Order.find(params[:id])
order.finish!(@current_user)
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
# Renders the fax-text-file
@ -107,9 +109,9 @@ class OrdersController < ApplicationController
supplier = order.supplier
contact = FoodsoftConfig[:contact].symbolize_keys
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\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 += "#{FoodsoftConfig[:name]}\n#{contact[:street]}\n#{contact[:zip_code]} #{contact[:city]}\n\n"
text += "****** " + I18n.t('orders.fax.articles') + "\n\n"

View File

@ -31,6 +31,11 @@ class StockitController < ApplicationController
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
@article = StockArticle.find(params[:id])
@article.mark_as_deleted
@ -55,9 +60,4 @@ class StockitController < ApplicationController
render :partial => 'form', :locals => {:stock_article => stock_article}
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

View File

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

View File

@ -73,6 +73,22 @@ module ApplicationHelper
link_to(text, url_for(url_options), html_options)
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
def link_to_top

View File

@ -155,7 +155,7 @@ class Order < ActiveRecord::Base
unless finished?
Order.transaction do
# 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
# Also save results for each group_order_result

View File

@ -12,7 +12,8 @@ class OrderArticle < ActiveRecord::Base
validate :article_and_price_exist
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
after_destroy :update_ordergroup_prices

View File

@ -66,7 +66,7 @@ class Ordergroup < Group
end
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
# This is the ordergroup job per euro performance
@ -90,7 +90,7 @@ class Ordergroup < Group
# Global average
def self.avg_jobs_per_euro
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
def account_updated

View File

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

View File

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

View File

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

View File

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

View File

@ -2,19 +2,19 @@
= t('.body').html_safe
%pre
= [t('.fields.status'),
t('simple_form.labels.defaults.order_number'),
t('simple_form.labels.article.name'),
t('simple_form.labels.article.note'),
t('simple_form.labels.article.manufacturer'),
t('simple_form.labels.article.origin'),
t('simple_form.labels.article.unit'),
t('simple_form.labels.defaults.price'),
t('simple_form.labels.defaults.tax'),
t('simple_form.labels.defaults.deposit'),
t('simple_form.labels.defaults.unit_quantity'),
Article.human_attribute_name(:order_number),
Article.human_attribute_name(:name),
Article.human_attribute_name(:note),
Article.human_attribute_name(:manufacturer),
Article.human_attribute_name(:origin),
Article.human_attribute_name(:unit),
Article.human_attribute_name(:price),
Article.human_attribute_name(:tax),
Article.human_attribute_name(:deposit),
Article.human_attribute_name(:unit_quantity),
t('.fields.season_amount'),
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),
:html => { :multipart => true } do |f|

View File

@ -61,8 +61,6 @@
return true;
}
});
enablePriceTooltips();
});
function mark_article_for_delivery(stock_article_id) {
@ -80,14 +78,6 @@
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|
= f.error_notification
= base_errors f.object

View File

@ -5,21 +5,18 @@
$('#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 = $(
'<%= j(render(:partial => 'stock_change', :locals => {:stock_change => @stock_change})) %>'
).addClass('success');
enablePriceTooltips(stock_change);
$('input.stock-change-quantity', stock_change).val(quantity);
$('#stock_changes').append(stock_change);
mark_article_for_delivery(<%= @stock_change.stock_article.id %>);
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);

View File

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

View File

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

View File

@ -1,16 +1,16 @@
- title t('.title')
%dl
%dt= t 'simple_form.labels.delivery.supplier'
%dt= heading_helper Delivery, :supplier
%dd= @delivery.supplier.name
%dt= t 'simple_form.labels.delivery.delivered_on'
%dt= heading_helper Delivery, :delivered_on
%dd= @delivery.delivered_on
%dt= t 'deliveries.invoice_amount'
%dd= link_to_invoice(@delivery)
- if @delivery.invoice
%dt= t 'deliveries.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
%h2= t '.title_articles'

View File

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

View File

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

View File

@ -5,7 +5,7 @@
%h3= t('.amount_change_for', article: @order_article.article.name)
.modal-body
= 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
= link_to t('ui.close'), '#', class: 'btn', data: {dismiss: 'modal'}
= form.submit t('ui.save'), class: 'btn btn-primary'

View File

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

View File

@ -1,38 +1,38 @@
- title t('.title', number: @invoice.number)
%p
%b= t('simple_form.labels.invoice.supplier') + ':'
%b= heading_helper(Invoice, :supplier) + ':'
= @invoice.supplier.name
- if @invoice.delivery
%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
- if @invoice.order
%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
%p
%b= t('simple_form.labels.invoice.number') + ':'
%b= heading_helper(Invoice, :number) + ':'
= @invoice.number
%p
%b= t('simple_form.labels.invoice.date') + ':'
%b= heading_helper(Invoice, :date) + ':'
= @invoice.date
%p
%b= t('simple_form.labels.invoice.paid_on') + ':'
%b= heading_helper(Invoice, :paid_on) + ':'
= @invoice.paid_on
%p
%b= t('simple_form.labels.invoice.amount') + ':'
%b= heading_helper(Invoice, :amount) + ':'
= number_to_currency @invoice.amount
%p
%b= t('simple_form.labels.invoice.deposit') + ':'
%b= heading_helper(Invoice, :deposit) + ':'
= number_to_currency @invoice.deposit
%p
%b= t('simple_form.labels.invoice.deposit_credit') + ':'
%b= heading_helper(Invoice, :deposit_credit) + ':'
= number_to_currency @invoice.deposit_credit
%p
%b= t('simple_form.labels.invoice.note') + ':'
%b= heading_helper(Invoice, :note) + ':'
=h @invoice.note
= link_to t('ui.edit'), edit_finance_invoice_path(@invoice)

View File

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

View File

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

View File

@ -3,16 +3,20 @@
$(function() {
#{data_to_js(@ordering_data)}
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});
setToleranceBehaviour(#{FoodsoftConfig[:tolerance_is_costly]});
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
.row-fluid
.well.pull-left
%button{type: "button", class: "close", data: {dismiss: 'alert'}}= '&times;'.html_safe
%h2= @order.name
%dl.dl-horizontal
- unless @order.note.blank?
@ -35,8 +39,17 @@
%dd= number_to_currency(@ordering_data[:available_funds])
.well.pull-right
%button{type: "button", class: "close", data: {dismiss: 'alert'}}= '&times;'.html_safe
= 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|
= f.hidden_field :lock_version
= f.hidden_field :order_id
@ -59,9 +72,9 @@
%th(style="width:20px")= t '.available'
%th#col_required= t '.amount'
%th{style: "width:15px;"}= t '.sum'
%tbody
%tbody.list
- @order.articles_grouped_by_category.each do |category, order_articles|
%tr.article-category
%tr.list-heading.article-category
%td
= category
%i.icon-tag

View File

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

View File

@ -22,7 +22,9 @@
Javascripts
\==================================================
/ 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
I18n.defaultLocale = "#{I18n.default_locale}";
I18n.locale = "#{I18n.locale}";
I18n.fallbacks = true;
= yield(:javascript)

View File

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

View File

@ -3,5 +3,6 @@
= form.hidden_field :stock_article_id
= "Menge (#{stock_change.stock_article.quantity_available})"
= form.text_field :quantity, :size => 5, :autocomplete => 'off'
%b= stock_change.stock_article.name
= "(#{number_to_currency(stock_change.stock_article.price)} / #{stock_change.stock_article.unit})"
%span{:data => {:toggle => :tooltip, :title => render(:partial => 'shared/article_price_info', :locals => {:article => stock_change.stock_article})}}
%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 %
= f.input :deposit
- 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
.form-actions
= 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
- for article in @stock_articles
%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 - article.quantity_available
%th= article.quantity_available
@ -56,7 +56,6 @@
%td= article.article_category.name
%td
= 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'),
class: 'btn btn-mini btn-danger', :remote => true
%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|
- if @supplier.shared_supplier
.alert.alert-success
= t 'suppliers.shared_supplier_note'
.alert.alert-info
= t 'suppliers.shared_supplier_note'
= f.hidden_field :shared_supplier_id
= f.input :name
= f.input :address

View File

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

View File

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

View File

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

View File

@ -3,22 +3,22 @@
%section
%dl.dl-horizontal
%dt= t 'simple_form.labels.task.name'
%dt= Task.human_attribute_name(:name)
%dd= @task.name
- if @task.description.present?
%dt= t 'simple_form.labels.defaults.description'
%dt= Task.human_attribute_name(:description)
%dd= simple_format(@task.description)
- if @task.due_date.present?
%dt= t '.due_date'
%dt= Task.human_attribute_name(:due_date)
%dd
= format_date(@task.due_date)
- if @task.periodic?
%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)
%dt= t 'simple_form.labels.task.user_list'
%dt= Task.human_attribute_name(:user_list)
%dd= task_assignments(@task)
%dt= t 'simple_form.labels.task.workgroup'
%dt= Task.human_attribute_name(:workgroup)
%dd
- if @task.workgroup
= link_to @task.workgroup.name, workgroup_tasks_path(workgroup_id: @task.workgroup_id)
@ -30,7 +30,7 @@
- unless @task.done?
= 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.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'
- if @task.periodic?
= 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)'
# 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
# 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
config.assets.version = '1.0'
# Do not enable database connection when precompiling assets
config.assets.initialize_on_precompile = false
# It would be nice not to enable database connection when precompiling assets,
# but i18n-js requires initialization, that's why it's on.
config.assets.initialize_on_precompile = true
end
end

View File

@ -35,6 +35,9 @@ Foodsoft::Application.configure do
# Expands the lines which load the assets
config.assets.debug = true
# Required for i18n-js
config.assets.initialize_on_precompile = true
# Configure hostname for action mailer
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
config.action_mailer.delivery_method = :smtp
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.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
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
require 'client_side_validations/simple_form' if defined?(::SimpleForm)
require 'client_side_validations/formtastic' if defined?(::Formtastic)
# Uncomment to disable uniqueness validator, possible security issue
# 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.
# 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
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
# Mailadresses are set in config/app_config.yml
config.middleware.use ExceptionNotifier,
:email_prefix => FoodsoftConfig[:notification]['email_prefix'],
:sender_address => FoodsoftConfig[:notification]['sender_address'],
:exception_recipients => FoodsoftConfig[:notification]['error_recipients']
config.middleware.use ExceptionNotification::Rack,
:email => {
:email_prefix => FoodsoftConfig[:notification]['email_prefix'],
:sender_address => FoodsoftConfig[:notification]['sender_address'],
:exception_recipients => FoodsoftConfig[:notification]['error_recipients']
}
end
end

View File

@ -1,98 +1,142 @@
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:
attributes:
article:
article_category: Kategorie
availability: Artikel ist verfügbar?
availability_short: verf.
deposit: Pfand
fc_price: Endpreis
fc_share: FC-Aufschlag
fc_price_short:
fc_share: FoodCoop-Aufschlag
fc_share_short: FC-Aufschlag
gross_price: Bruttopreis
manufacturer: Produzent
name: Name
note: Notiz
order_number: Bestellnummer
origin: Herkunft
price: Nettopreis
supplier: Lieferantin
tax: MwSt
unit: Einheit
unit_quantity: Gebindegröße
unit_quantity_short: GebGr
article_category:
description: Beschreibung
name: Name
delivery:
delivered_on: Lieferdatum
note: Notiz
supplier: Lieferantin
financial_transaction:
amount: Betrag
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:
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:
email: Email
first_name: Vorname
last_name: Nachname
name: Name
nick: Benutzername
ordergroup: Bestellgruppe
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:
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!
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:
task:
attributes:
done:
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:
article: Artikel
article_category: Artikelkategorie
@ -212,6 +256,11 @@ de:
workgroups:
members: Mitglieder
name: Name
application:
controller:
error_authn:
error_denied:
error_members_only: Diese Aktion ist nur für Mitglieder der Gruppe erlaubt!
article_categories:
create:
notice: Die Kategorie wurde gespeichert
@ -305,18 +354,21 @@ de:
error_nosel: Du hast keine Artikel ausgewählt
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>
title:
sync:
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_skip: Es müssen keine Artikel gelöscht werden.
title: Auslisten ...
price_short: Preis
submit: Alle löschen/aktualisieren
submit: Alle synchronisieren
title: Artikel mit externer Datenbank synchronisieren
unit_quantity_short: GebGr
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 ...
update_msg: ! 'Artikel müssen aktualisiert werden:'
update_msg: ! '%{count} Artikel müssen aktualisiert werden.'
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>
fields:
@ -326,102 +378,6 @@ de:
file_label: Bitte wähle eine kompatible Datei aus
submit: Datei 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:
add_stock_change:
how_many_units: Wie viele Einheiten (%{unit}) des Artikels »%{name}« liefern?
@ -521,38 +477,9 @@ de:
title: ! 'Sortiermatrix der Bestellung: %{name}, beendet am %{date}'
total: Insgesamt %{count} Artikel
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.'
feedback:
create:
notice: Das Feedback wurde erfolgreich verschickt. Vielen Dank!
@ -644,11 +571,13 @@ de:
create:
notice: Rechnung wurde erstellt.
financial_transactions:
create:
notice: Die Transaktion wurde gespeichert.
create_collection:
alert: ! 'Ein Fehler ist aufgetreten: %{error}'
notice: Alle Transaktionen wurden gespeichert.
controller:
create:
notice: Die Transaktion wurde gespeichert.
create_collection:
alert: ! 'Ein Fehler ist aufgetreten: %{error}'
error_note_required: Notiz wird benötigt!
notice: Alle Transaktionen wurden gespeichert.
index:
balance: ! 'Kontostand: %{balance}'
last_updated_at: (zuletzt aktualisiert vor %{when})
@ -677,6 +606,7 @@ de:
group_order_articles:
form:
amount_change_for: Mengenänderung für %{article}
result_hint: ! 'Einheit: %{unit}'
index:
amount: Betrag
amount_fc: Betrag(FC)
@ -712,6 +642,7 @@ de:
title: Rechnung %{number}
order_articles:
edit:
stock_alert: Preise von Lagerartikeln können nicht geändert werden!
title: Artikel aktualisieren
new:
title: Neuer gelieferter Artikel die Bestellung
@ -787,6 +718,8 @@ de:
new_funds: Neuer Kontostand
note: Notiz
price: Preis
reset_article_search: Suche zurücksetzen
search_article: Artikel suchen...
sum: Summe
sum_amount: ! 'Gesamtbestellmenge bisher:'
supplier: Lieferant
@ -875,15 +808,11 @@ de:
option_choose: Lieferantin/Lager auswählen
option_stock: Lager
order_pdf: PDF erstellen
select:
prompt: Bitte wählen
submit:
create: ! '%{model} speichern'
invite:
create: Einladung verschicken
message:
create: Nachricht verschicken
update: Änderungen speichern
tasks:
required_users: Es fehlen %{count} Mitstreiterinnen!
home:
@ -971,9 +900,11 @@ de:
title: Person einladen
new:
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>
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:
application1:
title: Foodsoft - %{title}
@ -1218,57 +1149,6 @@ de:
home: Startseite
title: Wiki
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:
edit:
title: Bestellgruppe bearbeiten
@ -1293,7 +1173,6 @@ de:
fax:
amount: Menge
articles: Artikel
customer_number: Kundennummer
delivery_day: Liefertag
heading: Bestellung für %{name}
name: Name
@ -1532,7 +1411,7 @@ de:
message:
private: Nachricht erscheint nicht im Foodsoft Posteingang
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
stock_article:
copy_stock_article:
@ -1547,74 +1426,6 @@ de:
required_users: Wieviel Benutzerinnen werden insgesamt benötigt?
tax: In Prozent, Standard sind 7,0
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:
messages:
send_as_email: Bekomme Nachrichten als Emails.
@ -1630,48 +1441,6 @@ de:
settings_group:
messages: Nachrichten
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
options:
settings:
@ -1725,15 +1494,6 @@ de:
title: Lagerartikel bearbeiten
form:
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:
article:
article: Artikel
@ -1759,6 +1519,15 @@ de:
new:
search_text: ! 'Suche nache Artikeln aus allen Katalogen:'
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:
notice: Lagerartikel wurde gespeichert.
stock_update:
@ -1794,11 +1563,6 @@ de:
show_deliveries: Zeige alle Lieferungen
update:
notice: Lieferant wurde aktualisiert
support:
array:
last_word_connector: ! ' und '
two_words_connector: ! ' und '
words_connector: ! ', '
tasks:
accept:
notice: Du hast die Aufgabe übernommen
@ -1854,8 +1618,8 @@ de:
show:
accept_task: Aufgabe übernehmen
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
due_date: Fälligkeitsdatum
hours: ! '%{count}h'
mark_done: Als erledigt markieren
reject_task: Aufgabe ablehnen
@ -1872,18 +1636,10 @@ de:
workgroup:
title: Aufgaben für %{workgroup}
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:
close: Schließen
delete: Löschen
edit: Bearbeiten
history: Verlauf anzeigen
marks:
close: ! '&times;'
success: <i class="icon icon-ok"></i>

View File

@ -1,98 +1,142 @@
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:
attributes:
article:
article_category: article category
article_category: Category
availability: Is article available?
deposit: deposit
fc_price: FC price
fc_share: FC share
gross_price: gross price
price: price
availability_short: avail.
deposit: Deposit
fc_price: FoodCoop price
fc_price_short: FC 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
unit: unit
unit_quantity: unit quantity
unit: Unit
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:
amount: amount
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:
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:
email: Email
first_name: First name
last_name: Last name
name: Name
nick: Username
ordergroup: Ordergroup
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:
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}!
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:
task:
attributes:
done:
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:
article: Article
article_category: Article category
@ -212,6 +256,11 @@ en:
workgroups:
members: members
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:
create:
notice: Category was stored
@ -305,20 +354,23 @@ en:
error_nosel: You have selected no articles
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>
title: Upload articles
sync:
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.
title: Outlist ...
title: Remove from list ...
price_short: Price
submit: Delete/update all
submit: Synchronize all
title: Synchronize articles with external database
unit_quantity_short: unit quantity
unit_quantity_short: Unit quantity
update:
body: ! '<p><i>Every article is shown twice. The old values are gray and the text fields contain the current values.</i></p>
<p><i>Differences with the old articles are marked yellow.</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.'
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:
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:
@ -328,109 +380,13 @@ en:
file_label: Please choose a compatible file
submit: Upload file
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:
add_stock_change:
how_many_units: ! 'How many units (%{unit}) to deliver? Stock article name: %{name}.'
create:
notice: Delivery was created. Please dont forget to create invoice!
create_stock_article:
notice: The new stock article »%{name}« was saved.
notice: The new stock article "%{name}" was saved.
destroy:
notice: Delivery was deleted.
edit:
@ -478,7 +434,7 @@ en:
update:
notice: Delivery was updated.
update_stock_article:
notice: The stock article »%{name}« was updated.
notice: The stock article "%{name}" was updated.
documents:
order_by_articles:
filename: Order %{name}-%{date} - by articles
@ -525,38 +481,9 @@ en:
one: One article in total
other: ! '%{count} articles in total'
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 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:
create:
notice: Your feedback was sent successfully. Thanks a lot!
@ -648,11 +575,13 @@ en:
create:
notice: Invoice was created
financial_transactions:
create:
notice: The transaction was saved.
create_collection:
alert: ! 'An error occured: %{error}'
notice: All transactions were saved.
controller:
create:
notice: The transaction was saved.
create_collection:
alert: ! 'An error occured: %{error}'
error_note_required: Note is required!
notice: All transactions were saved.
index:
balance: ! 'Balance of account: %{balance}'
last_updated_at: (last updated %{when} ago)
@ -681,6 +610,7 @@ en:
group_order_articles:
form:
amount_change_for: Change amount for %{article}
result_hint: ! 'Unit: %{unit}'
index:
amount: Amount
amount_fc: Amount(FC)
@ -716,6 +646,7 @@ en:
title: Invoice %{number}
order_articles:
edit:
stock_alert:
title: Update article
new:
title: Add delivered article to order
@ -791,6 +722,8 @@ en:
new_funds: New account balance
note: Note
price: Price
reset_article_search: Reset search
search_article: Search for article...
sum: Sum
sum_amount: Current amount
supplier: Supplier
@ -880,15 +813,11 @@ en:
option_choose: Choose supplier/stock
option_stock: Stock
order_pdf: Create PDF
select:
prompt: please select
submit:
create: save %{model}
invite:
create: send invitation
message:
create: send message
update: save changes
tasks:
required_users: ! '%{count} members are still needed!'
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!
changes_saved: Changes saved.
index:
due_date_format: ! '%A %d %b'
due_date_format: ! '%A %d %B'
messages:
title: Newest Messages
view_all: See all messages
@ -976,9 +905,11 @@ en:
title: Invite person
new:
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>
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:
application1:
title: Foodsoft - %{title}
@ -1223,57 +1154,6 @@ en:
home: Home
title: Wiki
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:
edit:
title: Edit ordergroups
@ -1298,7 +1178,6 @@ en:
fax:
amount: Amount
articles: Articles
customer_number: Customer number
delivery_day: Delivery day
heading: Order for %{name}
name: Name
@ -1314,7 +1193,7 @@ en:
prices: Prices (net/FC)
select_all: Select all
stockit: In stock
supplier: Supplier
supplier: Producer
title: Article
unit_quantity: Unit quantity
index:
@ -1396,7 +1275,7 @@ en:
notice: Page was created
cshow:
error_noexist: Page doesnt exist!
redirect_notice: Redirected from %{page} ..
redirect_notice: Redirected from %{page} ...
destroy:
notice: The page '%{page}' and all subpages have been deleted successfully.
edit:
@ -1537,7 +1416,7 @@ en:
message:
private: Message doesnt show in Foodsoft mail inbox
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
stock_article:
copy_stock_article:
@ -1552,74 +1431,6 @@ en:
required_users: How many users will be needed in total?
tax: In percentage, standard is 7,0
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:
messages:
send_as_email: Receive messages as emails.
@ -1635,48 +1446,6 @@ en:
settings_group:
messages: Messages
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'
options:
settings:
@ -1730,15 +1499,6 @@ en:
title: Edit stock articles
form:
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:
article:
article: Article
@ -1764,6 +1524,15 @@ en:
new:
search_text: ! 'Search for articles in all catalogues:'
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:
notice: Stock article was created.
stock_update:
@ -1799,11 +1568,6 @@ en:
show_deliveries: Show all deliveries
update:
notice: Supplier was updated
support:
array:
last_word_connector: ! ' and '
two_words_connector: ! ' and '
words_connector: ! ', '
tasks:
accept:
notice: You have accepted the task
@ -1859,15 +1623,15 @@ en:
show:
accept_task: Accept task
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
due_date: Due date
hours: ! '%{count}h'
mark_done: Mark task as done
reject_task: Reject task
title: Show task
update:
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:
more: Nothing to do? %{tasks_link} are tasks for sure.
tasks_link: Here
@ -1877,18 +1641,10 @@ en:
workgroup:
title: Tasks for %{workgroup}
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:
close: Close
delete: Delete
edit: Edit
history: Show history
marks:
close: ! '&times;'
success: <i class="icon icon-ok"></i>

View File

@ -1,98 +1,142 @@
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:
attributes:
article:
article_category: catégorie
article_category: Catégorie
availability: l'article est-il disponible?
deposit: consigne
fc_price: prix final
fc_share: supplément boufcoop
gross_price: prix brut
price: prix net
availability_short:
deposit: Consigne
fc_price: Prix final
fc_price_short:
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
unit: unité
unit_quantity: unités par lot
unit: Unité
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:
amount: montant
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:
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:
email: Email
first_name: Prénom
last_name: Nom de famille
name: Nom
nick: Identifiant
ordergroup: Cellule
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:
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}!
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:
task:
attributes:
done:
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:
article: Article
article_category: la nouvelle catégorie
@ -212,6 +256,11 @@ fr:
workgroups:
members: membres
name: nom
application:
controller:
error_authn:
error_denied:
error_members_only:
article_categories:
create:
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>
<p><i>Attention, les doublons ne sont pas automatiquement détectés.</p></i>.'
title:
sync:
outlist:
alert_used:
body: ! 'Les articles suivants ne sont plus dans la liste et seront donc <b>supprimés</b>:'
body_skip: Aucun article à supprimer.
title: Exclure de la liste...
@ -316,9 +368,9 @@ fr:
title: Synchroniser les articles avec la base de données extérieure
unit_quantity_short: U/L
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...
update_msg: ! 'Ces articles doivent être mis à jour:'
update_msg:
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>
@ -332,102 +384,6 @@ fr:
file_label: Merci de choisir un fichier compatible
submit: Transférer le fichier
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:
add_stock_change:
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
rows:
- Cellule
-
- Quantité
- Prix
title: ! 'Ordre des articles pour la commande: %{name}, close le %{date}'
@ -495,6 +452,7 @@ fr:
filename: Commande %{name}-%{date} - Répartition par cellules
rows:
- Nom de l'article
- Commandée
- Quantité
- Prix unitaire
- Unités par lot
@ -510,6 +468,7 @@ fr:
- Nom
- Nombre de lots
- Unité
- Prix/Unité
- Prix unitaire
total:
order_matrix:
@ -526,38 +485,9 @@ fr:
one: Un seul article
other: ! '%{count} articles au total'
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 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:
create:
notice: Ton commentaire a été transmis avec succès. Merci
@ -655,11 +585,13 @@ fr:
create:
notice: La facture a bien été définie.
financial_transactions:
create:
notice: La transaction a été sauvegardée.
create_collection:
alert: ! 'Une erreur s''est produite: %{error}'
notice: Les transactions ont été sauvegardées.
controller:
create:
notice: La transaction a été sauvegardée.
create_collection:
alert: ! 'Une erreur s''est produite: %{error}'
error_note_required:
notice: Les transactions ont été sauvegardées.
index:
balance: ! 'Solde: %{balance}'
last_updated_at: (dernière mise à jour il y a %{when})
@ -688,6 +620,7 @@ fr:
group_order_articles:
form:
amount_change_for: Modification de la quantité de %{article}
result_hint:
index:
amount: Montant
amount_fc: Montant(boufcoop)
@ -723,6 +656,7 @@ fr:
title: Facture %{number}
order_articles:
edit:
stock_alert:
title: Mettre à jour la liste des article
new:
title:
@ -802,6 +736,8 @@ fr:
new_funds: Nouveau solde
note: Note
price: Prix
reset_article_search:
search_article:
sum: Prix total
sum_amount: ! 'Quantité déjà commandée:'
supplier: Fourni par
@ -892,15 +828,11 @@ fr:
option_choose: Choix d'unE fournisseusE_r
option_stock: Stock
order_pdf: Générer un PDF
select:
prompt: Faire un choix
submit:
create: Définir %{model}
invite:
create: Envoyer une invitatio
message:
create: Envoyer un message
update: Sauvergarder les modifications
tasks:
required_users: Il manque encore %{count} camarades!
home:
@ -994,9 +926,11 @@ fr:
title: Engrainer une personne
new:
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>
success: La_le membre a été engrainéE avec succès!
js:
ordering:
confirm_change:
layouts:
application1:
title: Foodsoft - %{title}
@ -1224,57 +1158,6 @@ fr:
home: Page d'accueil
title: Wiki
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:
edit:
title: Modifier les cellules
@ -1288,7 +1171,7 @@ fr:
article_count: ! 'Articles commandés:'
name: Nom
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
units_full: Lots complet
units_ordered: Unités commandées
@ -1299,7 +1182,6 @@ fr:
fax:
amount: Quantité
articles: Articles
customer_number: Numéro de client de la coop
delivery_day: Jour de livraison
heading: Commande pour %{name}
name: Nom
@ -1536,7 +1418,7 @@ fr:
message:
private: Le message n'apparaîtra pas dans la boîte de réception du Foodsoft
order_article:
units_to_order: Nombre de lots livrés
units_to_order:
update_current_price: Modifie aussi le prix des commandes en cours
stock_article:
copy_stock_article:
@ -1551,74 +1433,6 @@ fr:
required_users: De combien de personnes avons-nous besoin au total?
tax: En pourcentage, le standard est de 7,0
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:
messages:
send_as_email: Transmettre les messages de la boufcoop par email
@ -1634,48 +1448,6 @@ fr:
settings_group:
messages: Messages
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
options:
settings:
@ -1731,15 +1503,6 @@ fr:
title: Modifier l'article
form:
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:
article:
article: Article
@ -1765,6 +1528,15 @@ fr:
new:
search_text: ! 'Rechercher des articles dans tous les catalogues:'
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:
notice: L'article a été sauvegardé.
stock_update:
@ -1804,11 +1576,6 @@ fr:
show_deliveries: Afficher tous les réapprovisionnements
update:
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:
accept:
notice: Tu as accepté ce boulot
@ -1868,8 +1635,8 @@ fr:
show:
accept_task: Te charger de ce boulot.
confirm_delete_group: Veux-tu vraiment supprimer ce boulot hebdomadaire?
confirm_delete_single:
delete_group: Supprimer ce boulot
due_date: Echéance
hours: ! '%{count}h'
mark_done: Marquer comme effectué
reject_task: Refuser ce boulot
@ -1886,18 +1653,10 @@ fr:
workgroup:
title: Agenda de l'%{workgroup}
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:
close: Fermer
delete: Supprimer
edit: Modifier
history: Afficher l'historique
marks:
close: ! '&times;'
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 :fill_new_stock_article_form
end
get :history
end
resources :suppliers do

View File

@ -20,4 +20,4 @@ Deploy to staging
bundle exec cap deploy
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
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
Das Bestellen ist der Hauptteil dieser Software und ein wenig kompliziert.
Hier starte ich den Versuch die Programmlogik in Text umzusetzen und
Das Bestellen ist der Hauptteil dieser Software und ein wenig kompliziert.
Hier starte ich den Versuch die Programmlogik in Text umzusetzen und
verweise auf die enstprechenden Controller bzw. Modelle.
Der relevante Controller ist OrderingController.
=== Bestellung "in Netz stellen"
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.
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.
Dabei werden auch die Attribute quantity, tolerance und quantity_to_order gespeichert.
Diese Mengen repraesentieren die Gesamtbestellung, also alle Bestellgruppen.
=== 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.
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
Gruppenkontostand, so wird die Preisspalte rot unterlegt und die Bestellung
Gruppenkontostand, so wird die Preisspalte rot unterlegt und die Bestellung
kann nicht gespeichert werden.
=== (gruppen)-Bestellung wird gespeichert
@ -67,27 +67,27 @@ Wir unterscheiden dehalb zwei Faelle:
Verringe Bestellung auf 2(1) um 19uhr.
=> Zeile mit created_on = 18uhr wird gelöscht und
in der Zeile mit created_on = 17uhr wird der Wert tolerance auf 1 gaendert.
=== Wer bekommt wieviel?
Diese Frage wird wie schon erwaehnt mittels der group_order_article_quantites -Tabelle
geloest.
geloest.
Beipspiel.
articel x mit unit_quantity = 5.
17uhr: gruppe a bestellt 2(3), weil sie auf jeden fall was von x bekommen will
18uhr: gruppe b bestellt 2(0)
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:
(gruppe a), 2(1), 17uhr (wurde um 19uhr von 2(3) auf 2(1) geaendert)
(gruppe b), 2(0), 18uhr
(gruppe a), 2(0), 19uhr.
die zuteilung wird dann wie folgt ermittelt:
zeile 1: gruppe a bekommt 2
zeile 2: gruppe b bekommt 2
zeile 3: gruppe a bekommt 1, weil jetzt das gebinde schon voll ist.
Endstand: insg. Bestellt wurden 6(1)
Gruppe a bekommt 3 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
tasks = Task.where(done: false, due_date: 1.day.from_now.to_date)
for task in tasks
puts "Send notifications for #{task.name} to .."
rake_say "Send notifications for #{task.name} to .."
for user in task.users
begin
Mailer.upcoming_tasks(user, task).deliver if user.settings.notify['upcoming_tasks'] == 1
rescue
puts "deliver aborted for #{user.email}.."
rake_say "deliver aborted for #{user.email}.."
end
end
end
@ -27,7 +27,7 @@ namespace :foodsoft do
begin
Mailer.not_enough_users_assigned(task, user).deliver
rescue
puts "deliver aborted for #{user.email}"
rake_say "deliver aborted for #{user.email}"
end
end
end
@ -47,3 +47,8 @@ namespace :foodsoft do
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_to_run = ENV['TASK']
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
end
end
@ -17,8 +17,14 @@ namespace :multicoops do
task :run_single => :environment do
task_to_run = ENV['TASK']
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
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 addons:add heroku-postgresql:dev --app "$APP"
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
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\.delivery_method\)\s*=.*|\2 = :smtp|' config/environments/${RAILS_ENV}.rb
# 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/environments/development.rb\)|#\1|' .gitignore
# make sure we have a full configuration
@ -85,6 +87,8 @@ else
Foodsoft::Application.config.secret_token = '`openssl rand -hex 128`'
EOF
fi
# update Gemfile.lock after Gemfile updates (required by heroku)
bundle install --quiet
# configure localeapp, manually to include environment
if [ "$LOCALEAPP_KEY" ]; then
cat >config/initializers/localeapp.rb <<EOF
@ -100,9 +104,8 @@ EOF
gem 'localeapp'" >>Gemfile
# also do not cache so we get locale updates
sed -i 's|\(#\s*\)\?\(config\.cache_classes\)\s*=.*|\2 = false|' config/environments/${RAILS_ENV}.rb
bundle exec localeapp pull
fi
# update Gemfile.lock after Gemfile updates (required by heroku)
bundle install --quiet
# TODO add more extensive database seed
# and push = deploy
@ -115,11 +118,9 @@ if !heroku run rake db:version >/dev/null 2>&1; then
else
heroku run rake db:migrate
fi
# get full translations so update works
[ "$LOCALEAPP_KEY" ] && heroku run localeapp pull
# restart just to be sure
heroku ps:restart
#heroku ps:restart
# return to original branch
git checkout -q "$ORIG_BRANCH" && git stash pop -q

View File

@ -1,7 +1,7 @@
require 'spec_helper'
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
it_behaves_like 'a valid locale file', locale_file
# 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
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