diff --git a/.gitignore b/.gitignore
index 0b4b3134..2bd55feb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,15 +1,18 @@
log/*.log
tmp/**/*
config/*.yml
+config/initializers/secret_token.rb
db/*.sqlite3
nbproject/
config/environments/development.rb
-capfile
-config/environments/fcschinke09.rb
*.swp
*~
public/**/*_cached.*
-config/initializers/session_store.rb
.idea
-.rvmrc
.get-dump.yml
+.sass-cache/
+doc/app/
+# Deployment tools
+Capfile
+config/deploy.rb
+config/deploy/*
diff --git a/.rbenv-version b/.rbenv-version
deleted file mode 100644
index 651f0b9a..00000000
--- a/.rbenv-version
+++ /dev/null
@@ -1 +0,0 @@
-1.8.7-p357
diff --git a/Gemfile b/Gemfile
index 9e61a966..5af84990 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,18 +1,61 @@
# A sample Gemfile
-source "http://rubygems.org"
-#ruby "1.8.7"
+source "https://rubygems.org"
+ruby "1.9.3"
-gem "rails", '2.3.17'
+gem "rails", '~> 3.2.9'
-gem 'mysql'
-gem "fastercsv"
-gem "prawn", '<=0.6.3'
-gem 'haml', '>=2.0.6'
-gem 'routing-filter', '0.0.1', :require => 'routing_filter'
-gem 'sqlite3-ruby'
-gem 'rdoc', '>= 2.4.2'
+# Gems used only for assets and not required
+# in production environments by default.
+group :assets do
+ gem 'sass-rails', '~> 3.2.3'
+ gem 'coffee-rails', '~> 3.2.1'
+
+ # 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 'mysql2'
+gem 'prawn'
+gem 'haml-rails'
+gem 'kaminari'
+gem 'client_side_validations'
+gem 'simple_form'
+gem 'inherited_resources'
+gem 'localize_input', :git => "git://github.com/bennibu/localize_input.git"
+gem 'wikicloth'
+gem 'daemons'
+gem 'twitter-bootstrap-rails'
+gem 'simple-navigation'
+gem 'simple-navigation-bootstrap'
+gem 'meta_search'
+gem 'acts_as_versioned', git: 'git://github.com/technoweenie/acts_as_versioned.git' # Use this instead of rubygem
+gem 'acts_as_tree'
+gem 'acts_as_configurable', git: 'git://github.com/bwalding/acts_as_configurable.git'
+gem 'resque'
+gem 'whenever', :require => false # For defining cronjobs, see config/schedule.rb
+
+group :production do
+ gem 'exception_notification', :require => 'exception_notifier'
+end
group :development do
- gem 'annotate'
- gem 'hirb'
+ gem 'sqlite3'
+
+ # Better error output
+ gem 'better_errors'
+ gem 'binding_of_caller'
+
+ # Re-enable rails benchmarker/profiler
+ gem 'ruby-prof'
+ gem 'test-unit'
+
+ # Get infos when not using proper eager loading
+ gem 'bullet'
+
+ # Hide assets requests in log
+ gem 'quiet_assets'
end
diff --git a/Gemfile.lock b/Gemfile.lock
index a4b84916..821735fd 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,57 +1,256 @@
-GEM
- remote: http://rubygems.org/
+GIT
+ remote: git://github.com/bennibu/localize_input.git
+ revision: 5eb188d2525a073d09e142cf8b0b04e6ace6e7b0
specs:
- actionmailer (2.3.17)
- actionpack (= 2.3.17)
- actionpack (2.3.17)
- activesupport (= 2.3.17)
- rack (~> 1.1.0)
- activerecord (2.3.17)
- activesupport (= 2.3.17)
- activeresource (2.3.17)
- activesupport (= 2.3.17)
- activesupport (2.3.17)
- annotate (2.4.0)
- fastercsv (1.5.4)
- haml (3.0.25)
- hirb (0.3.4)
- json (1.7.6)
- mysql (2.8.1)
- prawn (0.6.3)
- prawn-core (>= 0.6.3, < 0.7)
- prawn-format (>= 0.2.3, < 0.3)
- prawn-layout (>= 0.3.2, < 0.4)
- prawn-security (>= 0.1.1, < 0.2)
- prawn-core (0.6.3)
- prawn-format (0.2.3)
- prawn-core
- prawn-layout (0.3.2)
- prawn-security (0.1.1)
- rack (1.1.6)
- rails (2.3.17)
- actionmailer (= 2.3.17)
- actionpack (= 2.3.17)
- activerecord (= 2.3.17)
- activeresource (= 2.3.17)
- activesupport (= 2.3.17)
- rake (>= 0.8.3)
+ localize_input (0.1.0)
+
+GIT
+ remote: git://github.com/bwalding/acts_as_configurable.git
+ revision: cdf6f6f979019275b523d10684b748f08e2dd8e8
+ specs:
+ acts_as_configurable (0.0.1)
+ rake
+
+GIT
+ remote: git://github.com/technoweenie/acts_as_versioned.git
+ revision: 63b1fc8529d028fae632fe80ec0cb25df56cd76b
+ specs:
+ acts_as_versioned (0.6.0)
+ activerecord (>= 3.0.9)
+
+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)
+ builder (~> 3.0.0)
+ erubis (~> 2.7.0)
+ journey (~> 1.0.4)
+ rack (~> 1.4.5)
+ rack-cache (~> 1.2)
+ rack-test (~> 0.6.1)
+ sprockets (~> 2.2.1)
+ activemodel (3.2.13)
+ activesupport (= 3.2.13)
+ builder (~> 3.0.0)
+ activerecord (3.2.13)
+ activemodel (= 3.2.13)
+ activesupport (= 3.2.13)
+ 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)
+ multi_json (~> 1.0)
+ acts_as_tree (1.2.0)
+ activerecord (>= 3.0.0)
+ arel (3.0.2)
+ better_errors (0.2.0)
+ coderay (>= 1.0.0)
+ erubis (>= 2.7.0)
+ binding_of_caller (0.6.8)
+ builder (3.0.4)
+ bullet (4.3.0)
+ uniform_notifier
+ chronic (0.9.0)
+ client_side_validations (3.1.4)
+ coderay (1.0.8)
+ 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)
+ daemons (1.1.9)
+ erubis (2.7.0)
+ exception_notification (2.6.1)
+ actionmailer (>= 3.0.4)
+ execjs (1.4.0)
+ multi_json (~> 1.0)
+ expression_parser (0.9.0)
+ haml (3.1.7)
+ haml-rails (0.3.5)
+ actionpack (>= 3.1, < 4.1)
+ activesupport (>= 3.1, < 4.1)
+ haml (~> 3.1)
+ railties (>= 3.1, < 4.1)
+ has_scope (0.5.1)
+ hashery (2.0.1)
+ hike (1.2.1)
+ i18n (0.6.1)
+ inherited_resources (1.3.1)
+ has_scope (~> 0.5.0)
+ responders (~> 0.6)
+ journey (1.0.4)
+ jquery-rails (2.1.3)
+ railties (>= 3.1.0, < 5.0)
+ thor (~> 0.14)
+ json (1.7.7)
+ 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)
+ actionpack (>= 3.1)
+ less (~> 2.2.0)
+ libv8 (3.3.10.4)
+ mail (2.5.3)
+ i18n (>= 0.4.0)
+ mime-types (~> 1.16)
+ treetop (~> 1.4.8)
+ meta_search (1.1.3)
+ actionpack (~> 3.1)
+ activerecord (~> 3.1)
+ activesupport (~> 3.1)
+ polyamorous (~> 0.5.0)
+ mime-types (1.21)
+ multi_json (1.7.1)
+ mysql2 (0.3.11)
+ pdf-reader (1.2.0)
+ Ascii85 (~> 1.0.0)
+ hashery (~> 2.0)
+ ruby-rc4
+ polyamorous (0.5.0)
+ activerecord (~> 3.0)
+ polyglot (0.3.3)
+ prawn (0.12.0)
+ pdf-reader (>= 0.9.0)
+ ttfunk (~> 1.0.2)
+ quiet_assets (1.0.2)
+ railties (>= 3.1, < 5.0)
+ rack (1.4.5)
+ rack-cache (1.2)
+ rack (>= 0.4)
+ rack-protection (1.3.2)
+ 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)
+ bundler (~> 1.0)
+ railties (= 3.2.13)
+ railties (3.2.13)
+ actionpack (= 3.2.13)
+ activesupport (= 3.2.13)
+ rack-ssl (~> 1.3.2)
+ rake (>= 0.8.7)
+ rdoc (~> 3.4)
+ thor (>= 0.14.6, < 2.0)
rake (10.0.3)
- rdoc (3.12)
+ rdoc (3.12.2)
json (~> 1.4)
- routing-filter (0.0.1)
- sqlite3-ruby (1.2.4)
+ redis (3.0.2)
+ redis-namespace (1.2.1)
+ redis (~> 3.0.0)
+ responders (0.9.3)
+ railties (~> 3.1)
+ resque (1.23.0)
+ multi_json (~> 1.0)
+ redis-namespace (~> 1.0)
+ sinatra (>= 0.9.2)
+ vegas (~> 0.1.2)
+ ruby-prof (0.11.2)
+ ruby-rc4 (0.1.5)
+ sass (3.2.1)
+ sass-rails (3.2.5)
+ railties (~> 3.2.0)
+ sass (>= 3.1.10)
+ tilt (~> 1.3)
+ simple-navigation (3.9.0)
+ activesupport (>= 2.3.2)
+ simple-navigation-bootstrap (0.0.4)
+ simple-navigation (>= 3.7.0)
+ simple_form (2.0.3)
+ actionpack (~> 3.0)
+ activemodel (~> 3.0)
+ sinatra (1.3.3)
+ rack (~> 1.3, >= 1.3.6)
+ rack-protection (~> 1.2)
+ tilt (~> 1.3, >= 1.3.3)
+ sprockets (2.2.2)
+ hike (~> 1.2)
+ multi_json (~> 1.0)
+ rack (~> 1.0)
+ tilt (~> 1.1, != 1.3.0)
+ sqlite3 (1.3.6)
+ test-unit (2.5.3)
+ therubyracer (0.10.2)
+ libv8 (~> 3.3.10)
+ thor (0.17.0)
+ tilt (1.3.6)
+ treetop (1.4.12)
+ polyglot
+ polyglot (>= 0.3.1)
+ ttfunk (1.0.3)
+ twitter-bootstrap-rails (2.1.3)
+ actionpack (>= 3.1)
+ less-rails (~> 2.2.3)
+ railties (>= 3.1)
+ therubyracer (~> 0.10.2)
+ tzinfo (0.3.37)
+ uglifier (1.3.0)
+ execjs (>= 0.3.0)
+ multi_json (~> 1.0, >= 1.0.2)
+ uniform_notifier (1.1.1)
+ vegas (0.1.11)
+ rack (>= 1.0.0)
+ whenever (0.8.1)
+ activesupport (>= 2.3.4)
+ chronic (>= 0.6.3)
+ wikicloth (0.8.0)
+ builder
+ expression_parser
PLATFORMS
ruby
DEPENDENCIES
- annotate
- fastercsv
- haml (>= 2.0.6)
- hirb
- mysql
- prawn (<= 0.6.3)
- rails (= 2.3.17)
- rdoc (>= 2.4.2)
- routing-filter (= 0.0.1)
- sqlite3-ruby
+ acts_as_configurable!
+ acts_as_tree
+ acts_as_versioned!
+ better_errors
+ binding_of_caller
+ bullet
+ client_side_validations
+ coffee-rails (~> 3.2.1)
+ daemons
+ exception_notification
+ haml-rails
+ inherited_resources
+ jquery-rails
+ kaminari
+ localize_input!
+ meta_search
+ mysql2
+ prawn
+ quiet_assets
+ rails (~> 3.2.9)
+ resque
+ ruby-prof
+ sass-rails (~> 3.2.3)
+ simple-navigation
+ simple-navigation-bootstrap
+ simple_form
+ sqlite3
+ test-unit
+ therubyracer
+ twitter-bootstrap-rails
+ uglifier (>= 1.0.3)
+ whenever
+ wikicloth
diff --git a/MULTI_COOP_INSTALL b/MULTI_COOP_INSTALL
index 602306c4..843cffa3 100644
--- a/MULTI_COOP_INSTALL
+++ b/MULTI_COOP_INSTALL
@@ -1 +1,4 @@
-TODO..
\ No newline at end of file
+MULTI_COOP_INSTALL
+------------------
+
+TODO ...
\ No newline at end of file
diff --git a/README_DEVEL b/README_DEVEL
index 53d20372..e5e08a6d 100644
--- a/README_DEVEL
+++ b/README_DEVEL
@@ -38,16 +38,17 @@ Edit app_config.yml to suit your needs or just keep the defaults for now.
(4) Secret Token
-------------------
-The user session is stored in a cookie. To avoid misusing the cookies and its sensitive information, rails will encrypt it with a token. So copy the config file
+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/session_store.rb.SAMPLE config/initializers/session_store.rb
+ cp config/initializers/secret_token.rb.SAMPLE config/initializers/secret_token.rb
-and modify the token "config.action_controller.session"!
+and modify the token!!
(5) Required ruby and gems
-------------------
-We reccomend the using of rvm (https://rvm.beginrescueend.com/). Install rvm and get the lates ruby (1.8.7).
+We reccomend the using of 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
@@ -59,9 +60,7 @@ After that you get the other gems easily with (from project root):
(6) Create database (schema) and load defaults
--------------------------
- rake db:create
- rake db:schema:load
- rake db:seed
+ rake db:setup
With this, you also get a ready to go user with username 'admin' and password 'secret'.
@@ -69,5 +68,29 @@ With this, you also get a ready to go user with username 'admin' and password 's
(7) Try it out!
---------------
Start the WEBrick server to try it out:
-
- script/server
+
+ 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
diff --git a/Rakefile b/Rakefile
index fb6758a3..3d3dd484 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,10 +1,8 @@
+#!/usr/bin/env rake
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
-require(File.join(File.dirname(__FILE__), 'config', 'boot'))
-
+require File.expand_path('../config/application', __FILE__)
require 'rake'
-require 'rake/testtask'
-#require 'rake/rdoctask'
-require 'tasks/rails'
+Foodsoft::Application.load_tasks
diff --git a/public/images/b_browse.png b/app/assets/images/b_browse.png
similarity index 100%
rename from public/images/b_browse.png
rename to app/assets/images/b_browse.png
diff --git a/public/images/b_drop.png b/app/assets/images/b_drop.png
similarity index 100%
rename from public/images/b_drop.png
rename to app/assets/images/b_drop.png
diff --git a/public/images/b_edit.png b/app/assets/images/b_edit.png
similarity index 100%
rename from public/images/b_edit.png
rename to app/assets/images/b_edit.png
diff --git a/public/images/b_user.png b/app/assets/images/b_user.png
similarity index 100%
rename from public/images/b_user.png
rename to app/assets/images/b_user.png
diff --git a/public/images/b_users.png b/app/assets/images/b_users.png
similarity index 100%
rename from public/images/b_users.png
rename to app/assets/images/b_users.png
diff --git a/public/images/dots-white.gif b/app/assets/images/dots-white.gif
similarity index 100%
rename from public/images/dots-white.gif
rename to app/assets/images/dots-white.gif
diff --git a/public/images/error.png b/app/assets/images/error.png
similarity index 100%
rename from public/images/error.png
rename to app/assets/images/error.png
diff --git a/public/images/euro.png b/app/assets/images/euro.png
similarity index 100%
rename from public/images/euro.png
rename to app/assets/images/euro.png
diff --git a/public/images/euro_new.png b/app/assets/images/euro_new.png
similarity index 100%
rename from public/images/euro_new.png
rename to app/assets/images/euro_new.png
diff --git a/public/images/icon_message.gif b/app/assets/images/icon_message.gif
similarity index 100%
rename from public/images/icon_message.gif
rename to app/assets/images/icon_message.gif
diff --git a/public/images/lamp_grey.png b/app/assets/images/lamp_grey.png
similarity index 100%
rename from public/images/lamp_grey.png
rename to app/assets/images/lamp_grey.png
diff --git a/public/images/lamp_red.png b/app/assets/images/lamp_red.png
similarity index 100%
rename from public/images/lamp_red.png
rename to app/assets/images/lamp_red.png
diff --git a/public/images/loader.gif b/app/assets/images/loader.gif
similarity index 100%
rename from public/images/loader.gif
rename to app/assets/images/loader.gif
diff --git a/app/assets/images/rails.png b/app/assets/images/rails.png
new file mode 100644
index 00000000..d5edc04e
Binary files /dev/null and b/app/assets/images/rails.png differ
diff --git a/public/images/redbox_spinner.gif b/app/assets/images/redbox_spinner.gif
similarity index 100%
rename from public/images/redbox_spinner.gif
rename to app/assets/images/redbox_spinner.gif
diff --git a/public/images/save_pdf.png b/app/assets/images/save_pdf.png
similarity index 100%
rename from public/images/save_pdf.png
rename to app/assets/images/save_pdf.png
diff --git a/public/images/text_file.png b/app/assets/images/text_file.png
similarity index 100%
rename from public/images/text_file.png
rename to app/assets/images/text_file.png
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
new file mode 100644
index 00000000..df0ebc2f
--- /dev/null
+++ b/app/assets/javascripts/application.js
@@ -0,0 +1,118 @@
+//= require jquery
+//= require jquery-ui
+//= require jquery_ujs
+//= require twitter/bootstrap
+//= require jquery.tokeninput
+//= require bootstrap-datepicker
+//= require bootstrap-datepicker.de
+//= require jquery.observe_field
+//= require rails.validations
+//= require_self
+//= require ordering
+
+// Load following statements, when DOM is ready
+$(function() {
+
+ // Show/Hide a specific DOM element
+ $('a[data-toggle-this]').live('click', function() {
+ $($(this).data('toggle-this')).toggle();
+ return false;
+ });
+
+ // Remove this item from DOM
+ $('a[data-remove-this]').live('click', function() {
+ $($(this).data('remove-this')).remove();
+ return false;
+ });
+
+ // Check/Uncheck a single checkbox
+ $('[data-check-this]').live('click', function() {
+ var checkbox = $($(this).data('check-this'));
+ checkbox.attr('checked', !checkbox.is(':checked'));
+ highlightRow(checkbox);
+ return false;
+ });
+
+ // Check/Uncheck all checkboxes for a specific form
+ $('input[data-check-all]').live('click', function() {
+ var status = $(this).is(':checked')
+ $($(this).data('check-all')).find('input[type="checkbox"]').each(function() {
+ $(this).attr('checked', status);
+ highlightRow($(this));
+ });
+ });
+
+ // Submit form when changing a select menu.
+ $('form[data-submit-onchange] select').live('change', function() {
+ var confirmMessage = $(this).children(':selected').data('confirm');
+ if (confirmMessage) {
+ if (confirm(confirmMessage)) {
+ $(this).parents('form').submit();
+ }
+ } else {
+ $(this).parents('form').submit();
+ }
+ return false;
+ });
+
+ // Submit form when changing text of an input field
+ // Use jquery observe_field plugin
+ $('form[data-submit-onchange] input[type=text]').each(function() {
+ $(this).observe_field(1, function() {
+ $(this).parents('form').submit();
+ });
+ });
+
+ // Submit form when clicking on checkbox
+ $('form[data-submit-onchange] input[type=checkbox]:not(input[data-ignore-onchange])').click(function() {
+ $(this).parents('form').submit();
+ });
+
+ $('[data-redirect-to]').bind('change', function() {
+ var newLocation = $(this).children(':selected').val();
+ if (newLocation != "") {
+ document.location.href = newLocation;
+ }
+ });
+
+ // Remote paginations
+ $('div.pagination[data-remote] a').live('click', function() {
+ $.getScript($(this).attr('href'));
+ return false;
+ });
+
+ // Show and hide loader on ajax callbacks
+ $('*[data-remote]').bind('ajax:beforeSend', function() {
+ $('#loader').show();
+ });
+
+ $('*[data-remote]').bind('ajax:complete', function() {
+ $('#loader').hide();
+ });
+
+ // Disable submit button on ajax forms
+ $('form[data-remote]').bind('ajax:beforeSend', function() {
+ $(this).children('input[type="submit"]').attr('disabled', 'disabled');
+ });
+
+ // Use bootstrap datepicker for dateinput
+ $('.datepicker').datepicker({format: 'yyyy-mm-dd', weekStart: 1, language: 'de'});
+});
+
+
+// gives the row an yellow background
+function highlightRow(checkbox) {
+ var row = checkbox.parents('tr');
+ if (checkbox.is(':checked')) {
+ row.addClass('selected');
+ } else {
+ row.removeClass('selected');
+ }
+}
+
+// Use with auto_complete to set a unique id,
+// e.g. when the user selects a (may not unique) name
+// There must be a hidden field with the id 'hidden_field'
+function setHiddenId(text, li) {
+ $('hidden_id').value = li.id;
+}
\ No newline at end of file
diff --git a/app/assets/javascripts/bootstrap.js.coffee b/app/assets/javascripts/bootstrap.js.coffee
new file mode 100644
index 00000000..c9404a8e
--- /dev/null
+++ b/app/assets/javascripts/bootstrap.js.coffee
@@ -0,0 +1,4 @@
+jQuery ->
+ $("a[rel=popover]").popover()
+ $(".tooltip").tooltip()
+ $("a[rel=tooltip]").tooltip()
\ No newline at end of file
diff --git a/app/assets/javascripts/ordering.js b/app/assets/javascripts/ordering.js
new file mode 100644
index 00000000..a75d0541
--- /dev/null
+++ b/app/assets/javascripts/ordering.js
@@ -0,0 +1,187 @@
+// JavaScript that handles the dynamic ordering quantities on the ordering page.
+//
+// In a JavaScript block on the actual view, define the article data by calls to setData().
+// You should also set the available group balance through setGroupBalance(amount).
+//
+// Call setDecimalSeparator(char) to overwrite the default character "." with a localized value.
+
+var modified = false // indicates if anything has been clicked on this page
+var groupBalance = 0; // available group money
+var decimalSeparator = "."; // default decimal separator
+var toleranceIsCostly = true; // default tolerance behaviour
+var isStockit = false; // Wheter the order is from stock oder normal supplier
+
+// Article data arrays:
+var price = new Array();
+var unit = new Array(); // items per order unit
+var itemTotal = new Array(); // total item price
+var quantityOthers = new Array();
+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 setDecimalSeparator(character) {
+ decimalSeparator = character;
+}
+
+function setToleranceBehaviour(value) {
+ toleranceIsCostly = value;
+}
+
+function setStockit(value) {
+ isStockit = value;
+}
+
+function setGroupBalance(amount) {
+ groupBalance = amount;
+}
+
+function addData(orderArticleId, itemPrice, itemUnit, itemSubtotal, itemQuantityOthers, itemToleranceOthers, allocated, available) {
+ var i = orderArticleId;
+ price[i] = itemPrice;
+ unit[i] = itemUnit;
+ itemTotal[i] = itemSubtotal;
+ quantityOthers[i] = itemQuantityOthers;
+ toleranceOthers[i] = itemToleranceOthers;
+ itemsAllocated[i] = allocated;
+ quantityAvailable[i] = available;
+}
+
+function increaseQuantity(item) {
+ var value = Number($('#q_' + item).val()) + 1;
+ if (!isStockit || (value <= (quantityAvailable[item] + itemsAllocated[item]))) {
+ update(item, value, $('#t_' + item).val());
+ }
+}
+
+function decreaseQuantity(item) {
+ var value = Number($('#q_' + item).val()) - 1;
+ if (value >= 0) {
+ update(item, value, $('#t_' + item).val());
+ }
+}
+
+function increaseTolerance(item) {
+ var value = Number($('#t_' + item).val()) + 1;
+ update(item, $('#q_' + item).val(), value);
+}
+
+function decreaseTolerance(item) {
+ var value = Number($('#t_' + item).val()) - 1;
+ if (value >= 0) {
+ update(item, $('#q_' + item).val(), value);
+ }
+}
+
+function update(item, quantity, tolerance) {
+ // set modification flag
+ modified = true
+
+ // update hidden input fields
+ $('#q_' + item).val(quantity);
+ $('#t_' + item).val(tolerance);
+
+ // calculate how many units would be ordered in total
+ var units = calcUnits(unit[item], quantityOthers[item] + Number(quantity), toleranceOthers[item] + Number(tolerance));
+ if (unitCompletedFromTolerance(unit[item], quantityOthers[item] + Number(quantity), toleranceOthers[item] + Number(tolerance))) {
+ $('#units_' + item).html('' + String(units) + ' ');
+ } else {
+ $('#units_' + item).html(String(units));
+ }
+
+ // update used/unused quantity
+ var available = Math.max(0, units * unit[item] - quantityOthers[item]);
+ var q_used = Math.min(available, quantity);
+ // ensure that at least the amout of items this group has already been allocated is used
+ if (quantity >= itemsAllocated[item] && q_used < itemsAllocated[item]) {
+ q_used = itemsAllocated[item];
+ }
+ $('#q_used_' + item).html(String(q_used));
+ $('#q_unused_' + item).html(String(quantity - q_used));
+ $('#q_total_' + item).html(String(Number(quantity) + quantityOthers[item]));
+
+ // update used/unused tolerance
+ if (unit[item] > 1) {
+ available = Math.max(0, available - q_used - toleranceOthers[item]);
+ t_used = Math.min(available, tolerance);
+ $('#t_used_' + item).html(String(t_used));
+ $('#t_unused_' + item).html(String(tolerance - t_used));
+ $('#t_total_' + item).html(String(Number(tolerance) + toleranceOthers[item]));
+ }
+
+ // update total price
+ if(toleranceIsCostly == true) {
+ itemTotal[item] = price[item] * (Number(quantity) + Number(tolerance));
+ } else {
+ itemTotal[item] = price[item] * (Number(quantity));
+ }
+ $('#price_' + item + '_display').html(asMoney(itemTotal[item]));
+
+ // update missing units
+ var missing_units = unit[item] - (((quantityOthers[item] + Number(quantity)) % unit[item]) + Number(tolerance) + toleranceOthers[item])
+ if (missing_units < 0) {
+ missing_units = 0;
+ }
+ $('#missing_units_' + item).html(String(missing_units));
+
+ // update balance
+ updateBalance();
+}
+
+function asMoney(amount) {
+ return String(amount.toFixed(2)).replace(/\./, ",");
+}
+
+function calcUnits(unitSize, quantity, tolerance) {
+ var units = Math.floor(quantity / unitSize)
+ var remainder = quantity % unitSize
+ return units + ((remainder > 0) && (remainder + tolerance >= unitSize) ? 1 : 0)
+}
+
+function unitCompletedFromTolerance(unitSize, quantity, tolerance) {
+ var remainder = quantity % unitSize
+ return (remainder > 0 && (remainder + tolerance >= unitSize));
+}
+
+function updateBalance() {
+ // update total price and order balance
+ var total = 0;
+ for (i in itemTotal) {
+ total += itemTotal[i];
+ }
+ $('#total_price').html(asMoney(total));
+ var balance = groupBalance - total;
+ $('#new_balance').html(asMoney(balance));
+ $('#total_balance').val(asMoney(balance));
+ // determine bgcolor and submit button state according to balance
+ var bgcolor = '';
+ if (balance < 0) {
+ bgcolor = '#FF0000';
+ $('#submit_button').attr('disabled', 'disabled')
+ } else {
+ $('#submit_button').removeAttr('disabled')
+ }
+ // update bgcolor
+ for (i in itemTotal) {
+ $('#td_price_' + i).css('background-color', bgcolor);
+ }
+}
+
+$(function() {
+ $('input[data-increase_quantity]').click(function() {
+ increaseQuantity($(this).data('increase_quantity'));
+ });
+ $('input[data-decrease_quantity]').click(function() {
+ decreaseQuantity($(this).data('decrease_quantity'));
+ });
+ $('input[data-increase_tolerance]').click(function() {
+ increaseTolerance($(this).data('increase_tolerance'));
+ });
+ $('input[data-decrease_tolerance]').click(function() {
+ decreaseTolerance($(this).data('decrease_tolerance'));
+ });
+
+ $('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?'));
+ });
+});
diff --git a/vendor/plugins/acts_as_tree/test/abstract_unit.rb b/app/assets/stylesheets/.gitkeep
similarity index 100%
rename from vendor/plugins/acts_as_tree/test/abstract_unit.rb
rename to app/assets/stylesheets/.gitkeep
diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css
new file mode 100644
index 00000000..2b84d28d
--- /dev/null
+++ b/app/assets/stylesheets/application.css
@@ -0,0 +1,4 @@
+/*
+*= require bootstrap_and_overrides
+*= require token-input-bootstrappy
+*/
\ No newline at end of file
diff --git a/app/assets/stylesheets/bootstrap_and_overrides.css.less b/app/assets/stylesheets/bootstrap_and_overrides.css.less
new file mode 100644
index 00000000..52f2f108
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap_and_overrides.css.less
@@ -0,0 +1,210 @@
+@import "twitter/bootstrap/bootstrap";
+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');
+
+// 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';
+
+// Font Awesome
+@import "fontawesome";
+
+// Your custom LESS stylesheets goes here
+//
+// Since bootstrap was imported above you have access to its mixins which
+// 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
+//
+// Example:
+// @linkColor: #ff0000;
+
+
+// Bootstrap datepicker
+@import "datepicker";
+
+// Custom styles
+
+// Fix empty dd tags in horizontal dl, see https://github.com/twitter/bootstrap/issues/4062
+.dl-horizontal {
+ dd { .clearfix(); }
+}
+
+@mainRedColor: #ED0606;
+
+.logo {
+ margin: 10px 0 0 30px;
+ float: left;
+ font-size: 35px;
+ font-weight: bold;
+ display: block;
+ color: @mainRedColor;
+
+ span {
+ padding: 2px 4px;
+ color: #ffffff;
+ background-color: @mainRedColor;
+ }
+}
+
+
+section {
+ padding-bottom: 30px;
+ margin-bottom: 30px;
+ border-bottom: 1px solid #d3d3d3;
+}
+
+footer {
+ margin-top: 50px;
+ padding-top: 20px;
+ border-top: 1px solid lightGrey;
+}
+
+table {
+
+ a.sortdown:after {
+ content: ' \25BC';
+ }
+ a.sortup:after {
+ content: ' \25B2';
+ }
+
+ tr.article-category {
+ background-color: #efefef;
+ td:first-child {
+ text-align: left;
+ }
+ }
+ th.numeric, td.numeric {
+ text-align: right;
+ }
+ td.odd {
+ background-color: @tableBackgroundAccent;
+ }
+
+ tr.selected td {
+ background-color: @successBackground;
+ }
+}
+
+// Tasks ..
+.accepted {
+ color: #468847;
+}
+.unaccepted {
+ color: #B94A48;
+}
+
+// Wiki
+#wikiContent {
+ .editsection {
+ display: none;
+ }
+ .mw-headline a {
+ color: @textColor;
+ text-decoration: none;
+ }
+}
+
+// ordering
+span.used {
+ color: green;
+}
+span.unused {
+ color: red;
+}
+
+#order-footer, .article-info {
+ text-align: left;
+ z-index: 1;
+ position: fixed;
+ bottom: 0;
+ background-color: #E4EED6;
+ border-top: 2px solid #78B74E;
+
+ #total-sum {
+ width: 22em;
+ margin: .5em 2em 0 0;
+ float: right;
+ #order-button {
+ margin: .5em 0;
+
+ input:disabled {
+ background-color: red; }
+ }
+ }
+}
+
+#order-footer {
+ width: 100%;
+ right: 0;
+ left: 0;
+}
+
+.article-info {
+ z-index: 2;
+ width: 40em;
+ height: 8em;
+ border: none;
+ left: 30px;
+
+ .article-name {
+ text-align: center;
+ margin: 2px 0;
+ margin-bottom: 5px;
+ width: 100%;
+ font-weight: bold;
+ }
+ .pull-right {
+ width: 35%;
+ }
+ .pull-left {
+ width: 60%;
+ }
+}
+
+tr.order-article .article-info {
+ display: none;
+}
+
+tr.order-article:hover .article-info {
+ display: block;
+}
+
+
+// ********* Articles
+
+tr.just-updated {
+ color: #468847;
+}
+
+tr.unavailable {
+ color: #999;
+}
+
+// articles edit all
+.field_with_errors {
+ input, select {
+ border-color: red;
+ }
+}
+
+// ********* Tweaks & fixes
+
+// need more space for supplier&order information (in German, at least)
+.dl-horizontal {
+ dt { width: 160px; }
+ dd { margin-left: 170px; }
+}
diff --git a/app/assets/stylesheets/datepicker.less b/app/assets/stylesheets/datepicker.less
new file mode 100644
index 00000000..5d39c7aa
--- /dev/null
+++ b/app/assets/stylesheets/datepicker.less
@@ -0,0 +1,147 @@
+/*!
+ * Datepicker for Bootstrap
+ *
+ * Copyright 2012 Stefan Petre
+ * Improvements by Andrew Rowls
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+.datepicker {
+ top: 0;
+ left: 0;
+ padding: 4px;
+ margin-top: 1px;
+ .border-radius(4px);
+ &:before {
+ content: '';
+ display: inline-block;
+ border-left: 7px solid transparent;
+ border-right: 7px solid transparent;
+ border-bottom: 7px solid #ccc;
+ border-bottom-color: rgba(0,0,0,.2);
+ position: absolute;
+ top: -7px;
+ left: 6px;
+ }
+ &:after {
+ content: '';
+ display: inline-block;
+ border-left: 6px solid transparent;
+ border-right: 6px solid transparent;
+ border-bottom: 6px solid @white;
+ position: absolute;
+ top: -6px;
+ left: 7px;
+ }
+ >div {
+ display: none;
+ }
+ &.days div.datepicker-days {
+ display: block;
+ }
+ &.months div.datepicker-months {
+ display: block;
+ }
+ &.years div.datepicker-years {
+ display: block;
+ }
+ table{
+ margin: 0;
+ }
+ td,
+ th{
+ text-align: center;
+ width: 20px;
+ height: 20px;
+ .border-radius(4px);
+ }
+ td {
+ &.day:hover {
+ background: @grayLighter;
+ cursor: pointer;
+ }
+ &.old,
+ &.new {
+ color: @grayLight;
+ }
+ &.disabled,
+ &.disabled:hover {
+ background: none;
+ color: @grayLight;
+ cursor: default;
+ }
+ &.today,
+ &.today:hover,
+ &.today.disabled,
+ &.today.disabled:hover {
+ @todayBackground: lighten(@orange, 30%);
+ .buttonBackground(@todayBackground, spin(@todayBackground, 20));
+ }
+ &.active,
+ &.active:hover,
+ &.active.disabled,
+ &.active.disabled:hover {
+ .buttonBackground(@btnPrimaryBackground, spin(@btnPrimaryBackground, 20));
+ color: #fff;
+ text-shadow: 0 -1px 0 rgba(0,0,0,.25);
+ }
+ span {
+ display: block;
+ width: 23%;
+ height: 54px;
+ line-height: 54px;
+ float: left;
+ margin: 1%;
+ cursor: pointer;
+ .border-radius(4px);
+ &:hover {
+ background: @grayLighter;
+ }
+ &.disabled,
+ &.disabled:hover {
+ background:none;
+ color: @grayLight;
+ cursor: default;
+ }
+ &.active,
+ &.active:hover,
+ &.active.disabled,
+ &.active.disabled:hover {
+ .buttonBackground(@btnPrimaryBackground, spin(@btnPrimaryBackground, 20));
+ color: #fff;
+ text-shadow: 0 -1px 0 rgba(0,0,0,.25);
+ }
+ &.old {
+ color: @grayLight;
+ }
+ }
+ }
+
+ th.switch {
+ width: 145px;
+ }
+
+ thead tr:first-child th,
+ tfoot tr:first-child th {
+ cursor: pointer;
+ &:hover{
+ background: @grayLighter;
+ }
+ }
+ /*.dow {
+ border-top: 1px solid #ddd !important;
+ }*/
+}
+.input-append,
+.input-prepend {
+ &.date {
+ .add-on i {
+ display: block;
+ cursor: pointer;
+ width: 16px;
+ height: 16px;
+ }
+ }
+}
diff --git a/public/stylesheets/ie_hacks.css b/app/assets/stylesheets/ie_hacks.css
similarity index 100%
rename from public/stylesheets/ie_hacks.css
rename to app/assets/stylesheets/ie_hacks.css
diff --git a/public/stylesheets/sass/main.sass b/app/assets/stylesheets/main.sass
similarity index 91%
rename from public/stylesheets/sass/main.sass
rename to app/assets/stylesheets/main.sass
index cf223be7..6a92e70c 100644
--- a/public/stylesheets/sass/main.sass
+++ b/app/assets/stylesheets/main.sass
@@ -1,12 +1,12 @@
// colors which are used in the foodsoft
-!main_red = #ED0606
-!hover_yellow = #ffff72
-!boxContent = #e4eed6
-!lightGrey = #efefef
-!darkGreen = #78b74e
-!lightGreen = #e4eed6
+$main_red: #ED0606
+$hover_yellow: #ffff72
+$boxContent: #e4eed6
+$lightGrey: #efefef
+$darkGreen: #78b74e
+$lightGreen: #e4eed6
-/* General rules ...
+// General rules ...
body
:background-color #fff
:color black
@@ -26,27 +26,27 @@ body
:border
:width 2px
:style solid
- :color = !main_red
+ color: $main_red
a, a:visited
:text-decoration underline
:color black
a:hover
- :color = !main_red
+ color: $main_red
h1, h2
- :color = !main_red
+ color: $main_red
h1
:font-size 2.2em
:line-height 0.8em
:padding 1em 0 5px 5%
:margin 0 0 1em 0
- :border-bottom
+ :border-bottom
:width 1px
- :style dotted
- :color = !main_red
+ :style dotted
+ color: $main_red
h2
:font-size 1.4em
@@ -88,7 +88,7 @@ option
border-top: 1px solid #D7D7D7
margin: .2em 0
-span.click-me
+.click-me
cursor: pointer
.left
float: left
@@ -104,10 +104,15 @@ span.click-me
.hidden
display: none
+.warning
+ background: yellow
+ font-weight: bold
+ padding: 1px 10px
+
// ********************************* loginpage
#login
:margin auto
- :width 27em
+ :width 35em
:font-size 1.2em
#login #meta
@@ -124,7 +129,7 @@ span.click-me
#logo
- :background = !main_red
+ background: $main_red
:height 1.1em
:width 8em
:padding 0 20px
@@ -136,17 +141,17 @@ span.click-me
:margin 0
a, a:hover
:color white
- :background-color = !main_red
+ background-color: $main_red
:text-decoration none
a span
- :color = !main_red
+ color: $main_red
:background #FFF
:padding-right 0.1em
:font-weight bold
:border-top
:width 2px
:style dotted
- :color = !main_red
+ color: $main_red
#logininfo
:position absolute
@@ -162,7 +167,7 @@ span.click-me
:color #737272
:font-weight bold
a:hover
- :color = !main_red
+ color: $main_red
// ************************************* box structure
#main
@@ -268,8 +273,6 @@ table
:color #008000
tr.selected, tr.active
:background-color #ffffc2
- tr.click-me
- :cursor pointer
tr.ignored
color: grey
tr.success
@@ -290,7 +293,7 @@ table tfoot tr
:padding-top 0.8em
tr.edit_inline
- :background-color = !hover_yellow
+ background-color: $hover_yellow
td, span
:padding 0.5em 0.2em
@@ -318,15 +321,15 @@ td.currency, td.actions
:text-align right
:padding-right 0.5em
td.closed
- background: url(/images/arrow_right_red.png) no-repeat center left
+ background: image-url('arrow_right_red.png') no-repeat center left
a
display: block
text-decoration: none
padding-left: 20px
td.open
- background: url(/images/arrow_down_red.png) no-repeat center left
+ background: image-url('arrow_down_red.png') no-repeat center left
-// ************************************* for edit formulars */
+// ************************************* for edit formulars
div.edit_form
:border 2px solid #e3e3e3
:background #f5f5f5
@@ -345,7 +348,7 @@ div.edit_form
:border
:width 3px
:style solid
- :color = !main_red
+ color: $main_red
// ***************************************** other boxes */
@@ -384,7 +387,7 @@ div.box_title
:font-size 1.3em
div.column_content
- :background = !boxContent
+ background: $boxContent
:color black
:padding 10px
margin-bottom: 2em
@@ -411,7 +414,7 @@ li.check div.spinner
:display block
:height 5px
:width 21px
- :background-image url(/images/dots-white.gif)
+ :background-image image-url('dots-white.gif')
:line-height 16px
:float left
:margin-right 5px
@@ -439,7 +442,7 @@ table#order
-webkit-border-radius: 3px
padding: 0
th#col_required, th#col_tolerance
- :width 140px
+ :width 145px
th#col_packages, th#col_left_units
:width 50px
td.quantity, td.tolerance
@@ -453,7 +456,7 @@ table#order
:padding-left 10px
tfoot
tr
- :background-color = !lightGreen
+ background-color: $lightGreen
td
:padding-right 10px
#order-footer, .article-info
@@ -500,6 +503,7 @@ tr.order-article .article-info
display: none
tr.order-article:hover .article-info
display: block
+
// ********* Comments
#newComment
:margin 1em
@@ -555,6 +559,7 @@ ul.autocomplete
background-color: #fff
text-align: center
margin: 0 10px 10px 0
+
// *** wiki
#wiki_content
border-style: none
@@ -600,7 +605,8 @@ ul.autocomplete
margin: 0.3em 0 0 3.2em
padding: 0
list-style-image: none
- li margin-bottom: 0.1em
+ li
+ margin-bottom: 0.1em
a.new_wiki_link
color: grey
@@ -612,7 +618,7 @@ a.new_wiki_link
margin-bottom: 2em
width: 25em
border: 1px solid grey
- :background-color= !lightGrey
+ background-color: $lightGrey
h2
font-size: 1em
color: black
@@ -626,14 +632,13 @@ a.new_wiki_link
height: 1em
color: #ED0606
a
- :color = !main_red
- :text-decoration = none
+ color: $main_red
+ text-decoration: none
a:hover
- :text-decoration = underline
+ text-decoration: underline
#sidebar
float: right
width: 290px
- margin-top: -60px
#sidebar-links
margin-bottom: 18px
text-align: right
@@ -653,4 +658,4 @@ a.new_wiki_link
.wiki_version
#sidebar
margin-top: -23px
- border: 1px solid #78b74e
\ No newline at end of file
+ border: 1px solid #78b74e
diff --git a/public/stylesheets/print.css b/app/assets/stylesheets/print.scss
similarity index 95%
rename from public/stylesheets/print.css
rename to app/assets/stylesheets/print.scss
index acafac47..e5b1fb7c 100644
--- a/public/stylesheets/print.css
+++ b/app/assets/stylesheets/print.scss
@@ -294,14 +294,14 @@ td.currency, td.actions {
padding-right: 0.5em; }
td.closed {
- background: url(/images/arrow_right_red.png) no-repeat center left; }
+ background: image-url('arrow_right_red.png') no-repeat center left; }
td.closed a {
display: block;
text-decoration: none;
padding-left: 20px; }
td.open {
- background: url(/images/arrow_down_red.png) no-repeat center left; }
+ background: image-url('arrow_down_red.png') no-repeat center left; }
div.edit_form {
border: 2px solid #e3e3e3;
@@ -371,7 +371,7 @@ li.check div.spinner {
display: block;
height: 5px;
width: 21px;
- background-image: url(/images/dots-white.gif);
+ background-image: image-url('dots-white.gif');
line-height: 16px;
float: left;
margin-right: 5px;
@@ -516,25 +516,24 @@ ul.autocomplete .informal {
text-align: center;
margin: 0 10px 10px 0; }
-#wiki_content {
- border-style: none;
- color: black;
- line-height: 1.5em; }
-
.wiki_show, .wiki_version, .wiki_new, .wiki_edit, .wiki_all {
margin-top: 30px;
padding: 10px; }
- .wiki_show h1, .wiki_version h1, .wiki_new h1, .wiki_edit h1, .wiki_all h1 {
- padding-left: 0;
- padding-top: 10px;
- border-bottom-style: solid; }
- .wiki_show .column_content, .wiki_version .column_content, .wiki_new .column_content, .wiki_edit .column_content, .wiki_all .column_content {
- margin-bottom: 0; }
#wiki_content {
+ border: 1px solid grey;
+ margin-right: 300px;
+ padding: 10px;
+ color: black;
+ line-height: 1.5em;
min-height: 400px; }
#wiki_content span.editsection {
display: none; }
+ #wiki_content h1 {
+ padding-left: 0;
+ padding-top: 10px;
+ border: none;
+ margin-bottom: 10px; }
#wiki_content h2, #wiki_content h3, #wiki_content h4, #wiki_content h5, #wiki_content h6 {
background: transparent none repeat scroll 0 0;
border-bottom: 1px solid #AAAAAA;
@@ -593,8 +592,7 @@ a.new_wiki_link {
#sidebar {
float: right;
- width: 290px;
- margin-top: -60px; }
+ width: 290px; }
#sidebar #sidebar-links {
margin-bottom: 18px;
text-align: right; }
diff --git a/app/assets/stylesheets/token-input-bootstrappy.css b/app/assets/stylesheets/token-input-bootstrappy.css
new file mode 100644
index 00000000..859414e1
--- /dev/null
+++ b/app/assets/stylesheets/token-input-bootstrappy.css
@@ -0,0 +1,133 @@
+/* Example tokeninput style #2: Facebook style */
+ul.token-input-list-facebook {
+ overflow: hidden;
+ height: auto !important;
+ height: 1%;
+ width: 400px;
+ border: 1px solid #BBB;
+ cursor: text;
+ font-size: 12px;
+ font-family: Verdana, sans-serif;
+ min-height: 1px;
+ z-index: 999;
+ margin: 0;
+ padding: 0;
+ background-color: #fff;
+ list-style-type: none;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+}
+
+ul.token-input-list-facebook.token-input-focused-facebook {
+ border-color: rgba(82, 168, 236, 0.8);
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
+ outline: 0;
+ outline: thin dotted 9;
+}
+
+ul.token-input-list-facebook li input {
+ border: 0;
+ width: 100px;
+ padding: 3px 8px;
+ background-color: white;
+ margin: 2px 0;
+ -webkit-appearance: caret;
+}
+
+li.token-input-token-facebook {
+ overflow: hidden;
+ height: auto !important;
+ height: 15px;
+ margin: 3px;
+ padding: 1px 3px;
+ background-color: #F5F5F5;
+ color: #555;
+ cursor: default;
+ border: 1px solid #BBB;
+ font-size: 11px;
+ border-radius: 5px;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ float: left;
+ white-space: nowrap;
+}
+
+li.token-input-token-facebook p {
+ display: inline;
+ padding: 0;
+ margin: 0;
+}
+
+li.token-input-token-facebook span {
+ color: #a6b3cf;
+ margin-left: 5px;
+ font-weight: bold;
+ cursor: pointer;
+}
+
+li.token-input-selected-token-facebook {
+ background-color: #5670a6;
+ border: 1px solid #3b5998;
+ color: #fff;
+}
+
+li.token-input-input-token-facebook {
+ float: left;
+ margin: 0;
+ padding: 0;
+ list-style-type: none;
+}
+
+div.token-input-dropdown-facebook {
+ position: absolute;
+ width: 400px;
+ background-color: #F5F5F5;
+ overflow: hidden;
+ border-left: 1px solid #ccc;
+ border-right: 1px solid #ccc;
+ border-bottom: 1px solid #ccc;
+ cursor: default;
+ font-size: 12px;
+ font-family: Verdana, sans-serif;
+ z-index: 1;
+}
+
+div.token-input-dropdown-facebook p {
+ margin: 0;
+ padding: 5px;
+ font-weight: bold;
+ color: #555;
+}
+
+div.token-input-dropdown-facebook ul {
+ margin: 0;
+ padding: 0;
+}
+
+div.token-input-dropdown-facebook ul li {
+ background-color: #f5f5f5;
+ padding: 3px;
+ margin: 0;
+ list-style-type: none;
+}
+
+div.token-input-dropdown-facebook ul li.token-input-dropdown-item-facebook {
+ background-color: #f5f5f5;
+}
+
+div.token-input-dropdown-facebook ul li.token-input-dropdown-item2-facebook {
+ background-color: #f5f5f5;
+}
+
+div.token-input-dropdown-facebook ul li em {
+ font-weight: bold;
+ font-style: normal;
+}
+
+div.token-input-dropdown-facebook ul li.token-input-selected-dropdown-item-facebook {
+ background-color: #08C;
+ color: #f5f5f5;
+}
\ No newline at end of file
diff --git a/app/controllers/admin/ordergroups_controller.rb b/app/controllers/admin/ordergroups_controller.rb
index fb1c0356..358dc0c6 100644
--- a/app/controllers/admin/ordergroups_controller.rb
+++ b/app/controllers/admin/ordergroups_controller.rb
@@ -1,69 +1,23 @@
+# encoding: utf-8
class Admin::OrdergroupsController < Admin::BaseController
+ inherit_resources
def index
- if (params[:per_page] && params[:per_page].to_i > 0 && params[:per_page].to_i <= 100)
- @per_page = params[:per_page].to_i
- else
- @per_page = 20
+ @ordergroups = Ordergroup.undeleted.order('name ASC')
+
+ # if somebody uses the search field:
+ unless params[:query].blank?
+ @ordergroups = @ordergroups.where('name LIKE ?', "%#{params[:query]}%")
end
- # if the search field is used
- conditions = "name LIKE '%#{params[:query]}%'" unless params[:query].nil?
-
- @total = Ordergroup.without_deleted.count(:conditions => conditions )
- @ordergroups = Ordergroup.without_deleted.paginate(:conditions => conditions, :page => params[:page],
- :per_page => @per_page, :order => 'name')
-
- respond_to do |format|
- format.html # index.html.erb
- format.js { render :partial => "ordergroups" }
- end
- end
-
-
- def show
- @ordergroup = Ordergroup.find(params[:id])
- end
-
- def new
- @ordergroup = Ordergroup.new
- end
-
- def edit
- @ordergroup = Ordergroup.find(params[:id])
- end
-
- def create
- @ordergroup = Ordergroup.new(params[:ordergroup])
- @ordergroup.account_updated = Time.now
-
- if @ordergroup.save
- flash[:notice] = 'Ordergroup was successfully created.'
- redirect_to([:admin, @ordergroup])
- else
- render :action => "new"
- end
- end
-
- def update
- @ordergroup = Ordergroup.find(params[:id])
-
- if @ordergroup.update_attributes(params[:ordergroup])
- flash[:notice] = 'Ordergroup was successfully updated.'
- redirect_to([:admin, @ordergroup])
- else
- render :action => "edit"
- end
+ @ordergroups = @ordergroups.page(params[:page]).per(@per_page)
end
def destroy
@ordergroup = Ordergroup.find(params[:id])
- @ordergroup.destroy
-
- redirect_to(admin_ordergroups_url)
- end
-
- def memberships
- @group = Ordergroup.find(params[:id])
+ @ordergroup.mark_as_deleted
+ redirect_to admin_ordergroups_url, notice: t('admin.ordergroups.destroy.notice')
+ rescue => error
+ redirect_to admin_ordergroups_url, alert: t('admin.ordergroups.destroy.error')
end
end
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index ce2ada44..e83ecc11 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -1,69 +1,15 @@
class Admin::UsersController < Admin::BaseController
-
+ inherit_resources
+
def index
- if (params[:per_page] && params[:per_page].to_i > 0 && params[:per_page].to_i <= 100)
- @per_page = params[:per_page].to_i
- else
- @per_page = 20
+ @users = User.order('nick ASC')
+
+ # if somebody uses the search field:
+ unless params[:user_name].blank?
+ @users = @users.where("first_name LIKE :user_name OR last_name LIKE :user_name OR nick LIKE :user_name",
+ user_name: "%#{params[:user_name]}%")
end
- # if the search field is used
- conditions = "first_name LIKE '%#{params[:query]}%' OR last_name LIKE '%#{params[:query]}%'" unless params[:query].nil?
- @total = User.count(:conditions => conditions)
- @users = User.paginate :page => params[:page], :conditions => conditions, :per_page => @per_page, :order => 'nick'
-
- respond_to do |format|
- format.html # listUsers.haml
- format.js do
- render :update do |page|
- page.replace_html 'table', :partial => "users"
- end
- end
- end
+ @users = @users.page(params[:page]).per(@per_page)
end
-
- def show
- @user = User.find(params[:id])
- end
-
- def new
- @user = User.new
- end
-
- def create
- @user = User.new(params[:user])
- if @user.save
- flash[:notice] = 'Benutzerin wurde erfolgreich angelegt.'
- redirect_to admin_users_path
- else
- render :action => 'new'
- end
- end
-
- def edit
- @user = User.find(params[:id])
- end
-
- def update
- @user = User.find(params[:id])
- if @user.update_attributes(params[:user])
- flash[:notice] = 'Änderungen wurden gespeichert.'
- redirect_to [:admin, @user]
- else
- render :action => 'edit'
- end
- end
-
- def destroy
- user = User.find(params[:id])
- if user.nick == @current_user.nick
- # deny destroying logged-in-user
- flash[:error] = 'Du darfst Dich nicht selbst löschen.'
- else
- user.destroy
- flash[:notice] = 'Benutzer_in wurde gelöscht.'
- end
- redirect_to admin_users_path
- end
-
end
diff --git a/app/controllers/admin/workgroups_controller.rb b/app/controllers/admin/workgroups_controller.rb
index e01af47a..e7c88fe2 100644
--- a/app/controllers/admin/workgroups_controller.rb
+++ b/app/controllers/admin/workgroups_controller.rb
@@ -1,68 +1,20 @@
+# encoding: utf-8
class Admin::WorkgroupsController < Admin::BaseController
-
+ inherit_resources
+
def index
- if (params[:per_page] && params[:per_page].to_i > 0 && params[:per_page].to_i <= 100)
- @per_page = params[:per_page].to_i
- else
- @per_page = 20
- end
+ @workgroups = Workgroup.order('name ASC')
+ # if somebody uses the search field:
+ @workgroups = @workgroups.where('name LIKE ?', "%#{params[:query]}%") unless params[:query].blank?
- # if the search field is used
- conditions = "name LIKE '%#{params[:query]}%'" unless params[:query].nil?
-
- @total = Ordergroup.count(:conditions => conditions )
- @workgroups = Workgroup.paginate(:conditions => conditions, :page => params[:page],
- :per_page => @per_page, :order => 'name')
-
- respond_to do |format|
- format.html # index.html.erb
- format.js { render :partial => "workgroups" }
- end
- end
-
-
- def show
- @workgroup = Workgroup.find(params[:id])
- end
-
- def new
- @workgroup = Workgroup.new
- end
-
- def edit
- @workgroup = Workgroup.find(params[:id])
- end
-
- def create
- @workgroup = Workgroup.new(params[:workgroup])
-
- if @workgroup.save
- flash[:notice] = 'Workgroup was successfully created.'
- redirect_to([:admin, @workgroup])
- else
- render :action => "new"
- end
- end
-
- def update
- @workgroup = Workgroup.find(params[:id])
-
- if @workgroup.update_attributes(params[:workgroup])
- flash[:notice] = 'Workgroup was successfully updated.'
- redirect_to([:admin, @workgroup])
- else
- render :action => "edit"
- end
+ @workgroups = @workgroups.page(params[:page]).per(@per_page)
end
def destroy
@workgroup = Workgroup.find(params[:id])
@workgroup.destroy
-
- redirect_to(admin_workgroups_url)
- end
-
- def memberships
- @group = Workgroup.find(params[:id])
+ redirect_to admin_workgroups_url, notice: t('admin.ordergroups.destroy.notice')
+ rescue => error
+ redirect_to admin_workgroups_url, alert: t('admin.ordergroups.destroy.error')
end
end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 06307475..29b752a0 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -1,84 +1,54 @@
+# encoding: utf-8
class ApplicationController < ActionController::Base
- filter_parameter_logging :password, :password_confirmation # do not log passwort parameters
- before_filter :select_foodcoop, :authenticate, :store_controller
+ protect_from_forgery
+ before_filter :select_language, :select_foodcoop, :authenticate, :store_controller, :items_per_page, :set_redirect_to
after_filter :remove_controller
-
- # sends a mail, when an error occurs
- # see plugins/exception_notification
- include ExceptionNotifiable
# Returns the controller handling the current request.
def self.current
Thread.current[:application_controller]
end
-
- # Use this method to call a rake task,,
- # e.g. to deliver mails after there are created.
- def call_rake(task, options = {})
- options[:rails_env] ||= Foodsoft.env
- args = options.map { |n, v| "#{n.to_s.upcase}='#{v}'" }
- system "/usr/bin/rake #{task} #{args.join(' ')} --trace 2>&1 >> #{Rails.root}/log/rake.log &"
- end
-
protected
def current_user
- begin
- # check if there is a valid session and return the logged-in user (its object)
- if session[:user] and session[:foodcoop]
- # for shared-host installations. check if the cookie-subdomain fits to request.
- return User.current_user = User.find(session[:user]) if session[:foodcoop] == Foodsoft.env
- end
- rescue
- reset_session
- flash[:error]= _("An error has occurred. Please login again.")
- redirect_to :controller => 'login'
+ # check if there is a valid session and return the logged-in user (its object)
+ if session[:user_id] and params[:foodcoop]
+ # for shared-host installations. check if the cookie-subdomain fits to request.
+ @current_user ||= User.find_by_id(session[:user_id]) if session[:scope] == FoodsoftConfig.scope
end
end
+ helper_method :current_user
- def current_user=(user)
- session[:user], session[:foodcoop] = user.id, Foodsoft.env
- end
-
- def return_to
- session['return_to']
- end
-
- def return_to=(uri)
- session['return_to'] = uri
- end
-
def deny_access
- self.return_to = request.request_uri
- redirect_to :controller => '/login', :action => 'denied'
- return false
+ session[:return_to] = request.original_url
+ redirect_to login_url, :alert => 'Access denied!'
end
private
def authenticate(role = 'any')
# Attempt to retrieve authenticated user from controller instance or session...
- if !(user = current_user)
+ if !current_user
# No user at all: redirect to login page.
- self.return_to = request.request_uri
- redirect_to :controller => '/login'
- return false
+ session[:user_id] = nil
+ session[:return_to] = request.original_url
+ redirect_to login_url, :alert => 'Authentication required!'
else
# We have an authenticated user, now check role...
# Roles gets the user through his memberships.
hasRole = case role
- when "admin" then user.role_admin?
- when "finance" then user.role_finance?
- when "article_meta" then user.role_article_meta?
- when "suppliers" then user.role_suppliers?
- when "orders" then user.role_orders?
+ when "admin" then current_user.role_admin?
+ when "finance" then current_user.role_finance?
+ when "article_meta" then current_user.role_article_meta?
+ when "suppliers" then current_user.role_suppliers?
+ when "orders" then current_user.role_orders?
when "any" then true # no role required
else false # any unknown role will always fail
end
if hasRole
- @current_user = user
+ current_user
else
deny_access
end
@@ -110,12 +80,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?
- flash[:error] = "Diese Aktion ist nur für Mitglieder der Gruppe erlaubt!"
- if request.xml_http_request?
- render(:update) {|page| page.redirect_to root_path }
- else
- redirect_to root_path
- end
+ redirect_to root_path, alert: "Diese Aktion ist nur für Mitglieder der Gruppe erlaubt!"
end
end
@@ -138,23 +103,47 @@ class ApplicationController < ActionController::Base
# It uses the subdomain to select the appropriate section in the config files
# Use this method as a before filter (first filter!) in ApplicationController
def select_foodcoop
- if Foodsoft.config[:multi_coop_install]
- if !params[:foodcoop].blank?
+ if FoodsoftConfig[:multi_coop_install]
+ if params[:foodcoop].present?
begin
- # Set Config
- Foodsoft.env = params[:foodcoop]
- # Set database-connection
- ActiveRecord::Base.establish_connection(Foodsoft.database)
+ # Set Config and database connection
+ FoodsoftConfig.select_foodcoop params[:foodcoop]
rescue => error
- flash[:error] = error.to_s
- redirect_to root_path
+ redirect_to root_url, alert: error.message
end
else
- redirect_to root_path
+ redirect_to root_url
end
- else
- # Deactivate routing filter
- RoutingFilter::Foodcoop.active = false
end
end
+
+ def items_per_page
+ if params[:per_page] && params[:per_page].to_i > 0 && params[:per_page].to_i <= 100
+ @per_page = params[:per_page].to_i
+ else
+ @per_page = 20
+ end
+ end
+
+ def set_redirect_to
+ session[:redirect_to] = params[:redirect_to] if params[:redirect_to]
+ end
+
+ def back_or_default_path(default = root_path)
+ if session[:redirect_to].present?
+ default = session[:redirect_to]
+ session[:redirect_to] = nil
+ end
+ default
+ end
+
+ # Always stay in foodcoop url scope
+ def default_url_options(options = {})
+ {foodcoop: FoodsoftConfig.scope}
+ end
+
+ # Used to prevent accidently switching to :en in production mode.
+ def select_language
+ I18n.locale = :de
+ end
end
diff --git a/app/controllers/article_categories_controller.rb b/app/controllers/article_categories_controller.rb
index 944c1717..54710886 100644
--- a/app/controllers/article_categories_controller.rb
+++ b/app/controllers/article_categories_controller.rb
@@ -1,71 +1,27 @@
class ArticleCategoriesController < ApplicationController
+ inherit_resources # Build default REST Actions via plugin
+
before_filter :authenticate_article_meta
- def index
- @article_categories = ArticleCategory.all :order => 'name'
- end
-
- def new
- @article_category = ArticleCategory.new
-
- render :update do |page|
- page['category_form'].replace_html :partial => 'article_categories/form'
- page['category_form'].show
- end
- end
-
- def edit
- @article_category = ArticleCategory.find(params[:id])
-
- render :update do |page|
- page['category_form'].replace_html :partial => 'article_categories/form'
- page['category_form'].show
- end
- end
-
def create
- @article_category = ArticleCategory.new(params[:article_category])
-
- if @article_category.save
- render :update do |page|
- page['category_form'].hide
- page['category_list'].replace_html :partial => 'article_categories/list'
- page['category_'+@article_category.id.to_s].visual_effect(:highlight,
- :duration => 2)
- end
- else
- render :update do |page|
- page['category_form'].replace_html :partial => 'article_categories/form'
- end
- end
+ create!(:notice => I18n.t('article_categories.create.notice')) { article_categories_path }
end
def update
- @article_category = ArticleCategory.find(params[:id])
-
- if @article_category.update_attributes(params[:article_category])
- render :update do |page|
- page['category_form'].hide
- page['category_list'].replace_html :partial => 'article_categories/list'
- page['category_'+@article_category.id.to_s].visual_effect(:highlight,
- :duration => 2)
- end
- else
- render :update do |page|
- page['category_form'].replace_html :partial => 'article_categories/form'
- end
- end
+ update!(:notice => I18n.t('article_categories.update.notice')) { article_categories_path }
end
def destroy
- @article_category = ArticleCategory.find(params[:id])
- @article_category.destroy
-
- if @article_category.destroy
- render :update do |page|
- page['category_'+@article_category.id.to_s].visual_effect :drop_out
- end
- end
+ destroy!
+ rescue => error
+ redirect_to article_categories_path, alert: I18n.t('article_categories.destroy.error', message: error.message)
end
+
+ protected
+
+ def collection
+ @article_categories = ArticleCategory.order('name')
+ end
+
end
diff --git a/app/controllers/articles_controller.rb b/app/controllers/articles_controller.rb
index 75b953a5..2e834ab5 100644
--- a/app/controllers/articles_controller.rb
+++ b/app/controllers/articles_controller.rb
@@ -1,92 +1,53 @@
+# encoding: utf-8
class ArticlesController < ApplicationController
before_filter :authenticate_article_meta, :find_supplier
def index
- if (params[:per_page] && params[:per_page].to_i > 0 && params[:per_page].to_i <= 500)
- @per_page = params[:per_page].to_i
- else
- @per_page = 30
- end
-
if params['sort']
- sort = case params['sort']
- when "name" then "articles.name"
- when "unit" then "articles.unit"
- when "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 "note_reverse" then "articles.note DESC"
- when "availability_reverse" then "articles.availability DESC"
- end
+ sort = case params['sort']
+ when "name" then "articles.name"
+ when "unit" then "articles.unit"
+ when "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 "note_reverse" then "articles.note DESC"
+ when "availability_reverse" then "articles.availability DESC"
+ end
else
sort = "article_categories.name, articles.name"
end
- # if somebody uses the search field:
- conditions = ["articles.name LIKE ?", "%#{params[:query]}%"] unless params[:query].nil?
+ @articles = Article.undeleted.where(supplier_id: @supplier, :type => nil).includes(:article_category).order(sort)
+ @articles = @articles.where('articles.name LIKE ?', "%#{params[:query]}%") unless params[:query].nil?
- @total = @supplier.articles.without_deleted.count(:conditions => conditions)
- @articles = @supplier.articles.without_deleted.paginate(
- :order => sort,
- :conditions => conditions,
- :page => params[:page],
- :per_page => @per_page,
- :include => :article_category
- )
+ @articles = @articles.page(params[:page]).per(@per_page)
respond_to do |format|
- format.html # list.haml
- format.js do
- render :update do |page|
- page.replace_html 'table', :partial => "articles"
- end
- end
+ format.html
+ format.js { render :layout => false }
end
end
def new
@article = @supplier.articles.build(:tax => 7.0)
-
- render :update do |page|
- page["edit_article"].replace_html :partial => 'new'
- page["edit_article"].show
- end
+ render :layout => false
end
def create
@article = Article.new(params[:article])
if @article.valid? and @article.save
- render :update do |page|
- page.Element.hide('edit_article')
- page.insert_html :top, 'listbody', :partial => 'new_article_row'
- page[@article.id.to_s].visual_effect(:highlight,
- :duration => 2)
- # highlights article
- if !@article.availability
- page[@article.id.to_s].addClassName 'unavailable'
- else
- page[@article.id.to_s].addClassName 'just_updated'
- end
- end
+ render :layout => false
else
- render :update do |page|
- page.replace_html 'edit_article', :partial => "new"
- end
- end
+ render :action => 'new', :layout => false
+ end
end
- # edit an article and its price
def edit
@article = Article.find(params[:id])
-
- render :update do |page|
- page["edit_article"].replace_html :partial => 'edit'
- page["edit_article"].show
- end
- #render :partial => "quick_edit", :layout => false
+ render :action => 'new', :layout => false
end
# Updates one Article and highlights the line if succeded
@@ -94,112 +55,79 @@ class ArticlesController < ApplicationController
@article = Article.find(params[:id])
if @article.update_attributes(params[:article])
- render :update do |page|
- page["edit_article"].hide
- page[@article.id.to_s].replace_html :partial => 'article_row'
-
- # hilights an updated article if the article ist available
- page[@article.id.to_s].addClassName 'just_updated' if @article.availability
-
- # highlights an available article and de-highlights in other case
- if !@article.availability
- page[@article.id.to_s].addClassName 'unavailable'
- # remove updated-class
- page[@article.id.to_s].removeClassName 'just_updated'
- else
- page[@article.id.to_s].removeClassName 'unavailable'
- end
-
- page[@article.id.to_s].visual_effect(:highlight, :delay => 0.5, :duration => 2)
- end
+ render :layout => false
else
- render :update do |page|
- page["edit_article"].replace_html :partial => "edit"
- end
+ render :action => 'new', :layout => false
end
end
# Deletes article from database. send error msg, if article is used in a current order
def destroy
@article = Article.find(params[:id])
-
- @order = @article.in_open_order # If article is in an active Order, the Order will be returned
- if @order
- render :update do |page|
- page.insert_html :after, @article.id.to_s, :partial => 'destroyActiveArticle'
- end
- else
- @article.destroy
- render :update do |page|
- page[@article.id.to_s].remove
- end
- end
+ @article.mark_as_deleted unless @order = @article.in_open_order # If article is in an active Order, the Order will be returned
+ render :layout => false
end
# Renders a form for editing all articles from a supplier
def edit_all
- @articles = @supplier.articles.without_deleted
+ @articles = @supplier.articles.undeleted
end
# Updates all article of specific supplier
- # deletes all articles from params[outlisted_articles]
def update_all
- currentArticle = nil # used to find out which article caused a validation exception
+ invalid_articles = false
+
begin
Article.transaction do
unless params[:articles].blank?
# Update other article attributes...
- for id, attributes in params[:articles]
- currentArticle = Article.find(id)
- currentArticle.update_attributes!(attributes)
+ @articles = Article.find(params[:articles].keys)
+ @articles.each do |article|
+ unless article.update_attributes(params[:articles][article.id.to_s])
+ invalid_articles = true unless invalid_articles # Remember that there are validation errors
+ end
end
- end
- # delete articles
- if params[:outlisted_articles]
- params[:outlisted_articles].keys.each {|id| Article.find(id).destroy }
- end
- end
- # Successfully done.
- flash[:notice] = 'Alle Artikel und Preise wurden aktalisiert'
- redirect_to supplier_articles_path(@supplier)
- rescue => e
- # An error has occurred, transaction has been rolled back.
- if currentArticle
- @failedArticle = currentArticle
- flash[:error] = "Es trat ein Fehler beim Aktualisieren des Artikels '#{currentArticle.name}' auf: #{e.message}"
- params[:sync] ? redirect_to(supplier_articles_path(@supplier)) : render(:action => 'edit_all')
- else
- flash[:error] = "Es trat ein Fehler beim Aktualisieren der Artikel auf: #{e.message}"
- redirect_to supplier_articles_path(@supplier)
+ raise ActiveRecord::Rollback if invalid_articles # Rollback all changes
+ end
end
end
+
+ if invalid_articles
+ # An error has occurred, transaction has been rolled back.
+ flash.now.alert = I18n.t('articles.controller.error_invalid')
+ render :edit_all
+ else
+ # Successfully done.
+ redirect_to supplier_articles_path(@supplier), notice: I18n.t('articles.controller.update_all.notice')
+ end
end
# makes different actions on selected articles
def update_selected
- raise 'Du hast keine Artikel ausgewählt' if params[:selected_articles].nil?
+ raise I18n.t('articles.controller.error_nosel') if params[:selected_articles].nil?
articles = Article.find(params[:selected_articles])
-
- case params[:selected_action]
- when 'destroy'
- articles.each {|a| a.destroy }
- flash[:notice] = 'Alle gewählten Artikel wurden gelöscht'
- when 'setNotAvailable'
- articles.each {|a| a.update_attribute(:availability, false) }
- flash[:notice] = 'Alle gewählten Artikel wurden auf "nicht verfügbar" gesetzt'
- when 'setAvailable'
- articles.each {|a| a.update_attribute(:availability, true) }
- flash[:notice] = 'Alle gewählten Artikel wurden auf "verfügbar" gesetzt'
- else
- flash[:error] = 'Keine Aktion ausgewählt!'
+ Article.transaction do
+ case params[:selected_action]
+ when 'destroy'
+ articles.each(&:mark_as_deleted)
+ flash[:notice] = I18n.t('articles.controller.update_sel.notice_destroy')
+ when 'setNotAvailable'
+ articles.each {|a| a.update_attribute(:availability, false) }
+ flash[:notice] = I18n.t('articles.controller.update_sel.notice_unavail')
+ when 'setAvailable'
+ articles.each {|a| a.update_attribute(:availability, true) }
+ flash[:notice] = I18n.t('articles.controller.update_sel.notice_avail')
+ else
+ flash[:alert] = I18n.t('articles.controller.update_sel.notice_noaction')
+ end
end
# action succeded
- redirect_to supplier_articles_path(@supplier, :per_page => params[:per_page])
-
- rescue => e
- flash[:error] = 'Ein Fehler ist aufgetreten: ' + e
- redirect_to supplier_articles_path(@supplier, :per_page => params[:per_page])
+ redirect_to supplier_articles_url(@supplier, :per_page => params[:per_page])
+
+ rescue => error
+ redirect_to supplier_articles_url(@supplier, :per_page => params[:per_page]),
+ :alert => I18n.t('errors.general_msg', :msg => error)
end
# lets start with parsing articles from uploaded file, yeah
@@ -232,14 +160,13 @@ class ArticlesController < ApplicationController
:tax => row[:tax])
# stop parsing, when an article isn't valid
unless article.valid?
- raise article.errors.full_messages.join(", ") + " ..in line " + (articles.index(row) + 2).to_s
+ raise I18n.t('articles.controller.error_parse', :msg => article.errors.full_messages.join(", "), :line => (articles.index(row) + 2).to_s)
end
@articles << article
end
- flash.now[:notice] = @articles.size.to_s + " articles are parsed successfully."
- rescue => e
- flash[:error] = "An error has occurred: " + e.message
- redirect_to upload_supplier_articles_path(@supplier)
+ flash.now[:notice] = I18n.t('articles.controller.parse_upload.notice', :count => @articles.size)
+ rescue => error
+ redirect_to upload_supplier_articles_path(@supplier), :alert => I18n.t('errors.general_msg', :msg => error.message)
end
end
@@ -247,58 +174,40 @@ class ArticlesController < ApplicationController
def create_from_upload
begin
Article.transaction do
- for article_attributes in params[:articles]
- @supplier.articles.create!(article_attributes)
+ invalid_articles = false
+ @articles = []
+ params[:articles].each do |_key, article_attributes|
+ @articles << (article = @supplier.articles.build(article_attributes))
+ invalid_articles = true unless article.save
end
+
+ raise I18n.t('articles.controller.error_invalid') if invalid_articles
end
# Successfully done.
- flash[:notice] = "The articles are saved successfully"
- redirect_to supplier_articles_path(@supplier)
+ redirect_to supplier_articles_path(@supplier), notice: I18n.t('articles.controller.create_from_upload.notice', :count => @articles.size)
+
rescue => error
# An error has occurred, transaction has been rolled back.
- flash[:error] = "An error occured: #{error.message}"
- redirect_to upload_supplier_articles_path(@supplier)
+ flash.now[:error] = I18n.t('errors.general_msg', :msg => error.message)
+ render :parse_upload
end
end
# renders a view to import articles in local database
#
def shared
- conditions = []
- conditions << "supplier_id = #{@supplier.shared_supplier.id}"
- # check for keywords
- conditions << params[:import_query].split(' ').collect { |keyword| "name LIKE '%#{keyword}%'" }.join(' AND ') unless params[:import_query].blank?
- # check for regional articles
- conditions << "origin = 'REG'" if params[:regional]
-
- @articles = SharedArticle.paginate :page => params[:page], :per_page => 10, :conditions => conditions.join(" AND ")
- render :update do |page|
- page.replace_html 'search_results', :partial => "import_search_results"
- end
+ # build array of keywords, required for meta search _all suffix
+ params[:search][:name_contains_all] = params[:search][:name_contains_all].split(' ') if params[:search]
+ # Build search with meta search plugin
+ @search = @supplier.shared_supplier.shared_articles.search(params[:search])
+ @articles = @search.page(params[:page]).per(10)
+ render :layout => false
end
# fills a form whith values of the selected shared_article
def import
- shared_article = SharedArticle.find(params[:shared_article_id])
- @article = Article.new(
- :supplier_id => params[:supplier_id],
- :name => shared_article.name,
- :unit => shared_article.unit,
- :note => shared_article.note,
- :manufacturer => shared_article.manufacturer,
- :origin => shared_article.origin,
- :price => shared_article.price,
- :tax => shared_article.tax,
- :deposit => shared_article.deposit,
- :unit_quantity => shared_article.unit_quantity,
- :order_number => shared_article.number,
- # convert to db-compatible-string
- :shared_updated_on => shared_article.updated_on.to_formatted_s(:db))
-
- render :update do |page|
- page["edit_article"].replace_html :partial => 'new'
- page["edit_article"].show
- end
+ @article = SharedArticle.find(params[:shared_article_id]).build_new_article
+ render :action => 'new', :layout => false
end
# sync all articles with the external database
@@ -306,16 +215,43 @@ class ArticlesController < ApplicationController
def sync
# check if there is an shared_supplier
unless @supplier.shared_supplier
- flash[:error]= "#{@supplier.name} ist nicht mit einer externen Datenbank verknüpft."
- redirect_to supplier_articles_path(@supplier)
+ redirect_to supplier_articles_url(@supplier), :alert => I18n.t('articles.controller.sync.shared_alert', :supplier => @supplier.name)
end
# sync articles against external database
@updated_articles, @outlisted_articles = @supplier.sync_all
# convert to db-compatible-string
@updated_articles.each {|a, b| a.shared_updated_on = a.shared_updated_on.to_formatted_s(:db)}
if @updated_articles.empty? && @outlisted_articles.empty?
- flash[:notice] = "Der Katalog ist aktuell."
- redirect_to supplier_articles_path(@supplier)
+ redirect_to supplier_articles_path(@supplier), :notice => I18n.t('articles.controller.sync.notice')
end
end
-end
\ No newline at end of file
+
+ # Updates, deletes articles when sync form is submitted
+ def update_synchronized
+ begin
+ Article.transaction do
+ # delete articles
+ if params[:outlisted_articles]
+ Article.find(params[:outlisted_articles].keys).each(&:mark_as_deleted)
+ end
+
+ # Update articles
+ params[:articles].each do |id, attrs|
+ Article.find(id).update_attributes! attrs
+ end
+ end
+
+ # Successfully done.
+ redirect_to supplier_articles_path(@supplier), notice: I18n.t('articles.controller.update_sync.notice')
+
+ rescue ActiveRecord::RecordInvalid => invalid
+ # An error has occurred, transaction has been rolled back.
+ redirect_to supplier_articles_path(@supplier),
+ alert: I18n.t('articles.controller.error_update', :article => invalid.record.name, :msg => invalid.record.errors.full_messages)
+
+ rescue => error
+ redirect_to supplier_articles_path(@supplier),
+ alert: I18n.t('errors.general_msg', :msg => error.message)
+ end
+ end
+end
diff --git a/app/controllers/deliveries_controller.rb b/app/controllers/deliveries_controller.rb
index 76b0fa9a..d8876c16 100644
--- a/app/controllers/deliveries_controller.rb
+++ b/app/controllers/deliveries_controller.rb
@@ -1,3 +1,4 @@
+# encoding: utf-8
class DeliveriesController < ApplicationController
before_filter :find_supplier, :exclude => :fill_new_stock_article_form
@@ -34,7 +35,7 @@ class DeliveriesController < ApplicationController
respond_to do |format|
if @delivery.save
- flash[:notice] = 'Lieferung wurde erstellt. Bitte nicht vergessen die Rechnung anzulegen!'
+ flash[:notice] = I18n.t('deliveries.create.notice')
format.html { redirect_to([@supplier,@delivery]) }
format.xml { render :xml => @delivery, :status => :created, :location => @delivery }
else
@@ -53,7 +54,7 @@ class DeliveriesController < ApplicationController
respond_to do |format|
if @delivery.update_attributes(params[:delivery])
- flash[:notice] = 'Lieferung wurde aktualisiert.'
+ flash[:notice] = I18n.t('deliveries.update.notice')
format.html { redirect_to([@supplier,@delivery]) }
format.xml { head :ok }
else
@@ -67,7 +68,7 @@ class DeliveriesController < ApplicationController
@delivery = Delivery.find(params[:id])
@delivery.destroy
- flash[:notice] = "Lieferung wurde gelöscht."
+ flash[:notice] = I18n.t('deliveries.destroy.notice')
respond_to do |format|
format.html { redirect_to(supplier_deliveries_url(@supplier)) }
format.xml { head :ok }
@@ -92,11 +93,7 @@ class DeliveriesController < ApplicationController
end
def add_stock_change
-
- render :update do |page|
- page.insert_html :bottom, 'stock_changes', :partial => 'stock_change',
- :locals => {:stock_change => StockChange.new, :supplier => @supplier}
- end
+ render :layout => false
end
def fill_new_stock_article_form
diff --git a/app/controllers/feedback_controller.rb b/app/controllers/feedback_controller.rb
index 1e4be46f..14c22849 100644
--- a/app/controllers/feedback_controller.rb
+++ b/app/controllers/feedback_controller.rb
@@ -1,19 +1,14 @@
class FeedbackController < ApplicationController
def new
- render :update do |page|
- page.replace_html :ajax_box, :partial => "new"
- page.show :ajax_box
- end
end
def create
- unless params[:message].blank?
- Mailer.deliver_feedback(current_user, params[:message])
- end
-
- render :update do |page|
- page.replace_html :ajax_box, :partial => "success"
+ if params[:message].present?
+ Mailer.feedback(current_user, params[:message]).deliver
+ redirect_to root_url, notice: t('feedback.create.notice')
+ else
+ render :action => 'new'
end
end
diff --git a/app/controllers/finance/balancing_controller.rb b/app/controllers/finance/balancing_controller.rb
index 73ff59f5..8528e4d3 100644
--- a/app/controllers/finance/balancing_controller.rb
+++ b/app/controllers/finance/balancing_controller.rb
@@ -1,283 +1,50 @@
-class Finance::BalancingController < ApplicationController
- before_filter :authenticate_finance
- verify :method => :post, :only => [:close, :close_direct]
-
- def index
- @financial_transactions = FinancialTransaction.find(:all, :order => "created_on DESC", :limit => 8)
- @orders = Order.finished_not_closed
- @unpaid_invoices = Invoice.unpaid
- end
+# encoding: utf-8
+class Finance::BalancingController < Finance::BaseController
- def list
- @orders = Order.finished.paginate :page => params[:page], :per_page => 10, :order => 'ends DESC'
+ def index
+ @orders = Order.finished.page(params[:page]).per(@per_page).order('ends DESC')
end
def new
- @order = Order.find(params[:id])
+ @order = Order.find(params[:order_id])
+ flash.now.alert = t('finance.balancing.new.alert') if @order.closed?
@comments = @order.comments
- if params['sort']
- sort = case params['sort']
- when "name" then "articles.name"
- when "order_number" then "articles.order_number"
- when "name_reverse" then "articles.name DESC"
- when "order_number_reverse" then "articles.order_number DESC"
- end
- else
- sort = "id"
- end
+ @articles = @order.order_articles.ordered.includes(:article, :article_price,
+ group_order_articles: {group_order: :ordergroup})
- @articles = @order.order_articles.ordered.find(
- :all,
- :include => :article,
- :order => sort
- )
-
- if params[:sort] == "order_number"
- @articles = @articles.sort { |a,b| a.article.order_number.gsub(/[^[:digit:]]/, "").to_i <=> b.article.order_number.gsub(/[^[:digit:]]/, "").to_i }
- elsif params[:sort] == "order_number_reverse"
- @articles = @articles.sort { |a,b| b.article.order_number.gsub(/[^[:digit:]]/, "").to_i <=> a.article.order_number.gsub(/[^[:digit:]]/, "").to_i }
- end
+ sort_param = params['sort'] || 'name'
+ @articles = case sort_param
+ when 'name' then
+ OrderArticle.sort_by_name(@articles)
+ when 'name_reverse' then
+ OrderArticle.sort_by_name(@articles).reverse
+ when 'order_number' then
+ OrderArticle.sort_by_order_number(@articles)
+ when 'order_number_reverse' then
+ OrderArticle.sort_by_order_number(@articles).reverse
+ else
+ @articles
+ end
- view = params[:view]
- params[:view] = nil
+ render layout: false if request.xhr?
+ end
- case view
- when 'editResults'
- render :partial => 'edit_results_by_articles' and return
- when 'groupsOverview'
- render :partial => 'shared/articles_by_groups', :locals => {:order => @order} and return
- when 'articlesOverview'
- render :partial => 'shared/articles_by_articles', :locals => {:order => @order} and return
- end
+ def update_summary
+ @order = Order.find(params[:id])
end
def edit_note
@order = Order.find(params[:id])
- render :partial => 'edit_note'
+ render :layout => false
end
def update_note
@order = Order.find(params[:id])
- render :update do |page|
- if @order.update_attributes(params[:order])
- page["note"].replace_html simple_format(@order.note)
- page["edit_box"].hide
- else
- page["results"].replace_html :partial => "edit_note"
- end
- end
- end
-
- def new_order_article
- @order = Order.find(params[:id])
- render :update do |page|
- page["edit_box"].replace_html :partial => "new_order_article"
- page["edit_box"].show
- end
- end
-
- def auto_complete_for_article_name
- order = Order.find(params[:order_id])
- find_params = {
- :conditions => ["LOWER(articles.name) LIKE ?", "%#{params[:article][:name].downcase}%" ],
- :order => 'articles.name ASC',
- :limit => 8
- }
- @articles = if order.stockit?
- StockArticle.all find_params
+ if @order.update_attributes(params[:order])
+ render :layout => false
else
- order.supplier.articles.all find_params
- end
-
- render :partial => 'shared/auto_complete_articles'
- end
-
- def create_order_article
- @order = Order.find(params[:order_id])
- article = Article.find(params[:order_article][:article_id])
- order_article = @order.order_articles.find_by_article_id(article.id)
-
- unless order_article
- # Article wasn't already assigned with this order, lets create a new one
- order_article = @order.order_articles.build(params[:order_article])
- order_article.article_price = order_article.article.article_prices.first
- end
- # Set units to order to 1, so the article is visible on page
- order_article.units_to_order = 1
-
- render :update do |page|
- if order_article.save
- page["edit_box"].hide
- page.insert_html :top, "result_table", :partial => "order_article_result", :locals => {:order_article => order_article}
- page["order_article_#{order_article.id}"].visual_effect :highlight, :duration => 2
- page["group_order_articles_#{order_article.id}"].show
- else
- page["edit_box"].replace_html :partial => "new_order_article"
- end
- end
-
- rescue
- render :update do |page|
- page.replace_html "edit_box", :text => "Keinen Artikel gefunden. Bitte erneut versuchen. "
- page.insert_html :bottom, "edit_box", :partial => "new_order_article"
- end
- end
-
- def edit_order_article
- @order_article = OrderArticle.find(params[:id])
- render :update do |page|
- page["edit_box"].replace_html :partial => 'edit_order_article'
- page["edit_box"].show
- end
- end
-
- # Update this article and creates a new articleprice if neccessary
- def update_order_article
- @order_article = OrderArticle.find(params[:id])
- begin
- @order_article.update_article_and_price!(params[:article], params[:price], params[:order_article], params[:price_global])
- render :update do |page|
- page["edit_box"].hide
- page["summary"].replace_html :partial => 'summary', :locals => {:order => @order_article.order}
- page["summary"].visual_effect :highlight, :duration => 2
- page["order_article_#{@order_article.id}"].replace_html :partial => 'order_article', :locals => {:order_article => @order_article}
- page["order_article_#{@order_article.id}"].visual_effect :highlight, :delay => 0.5, :duration => 2
- page["group_order_articles_#{@order_article.id}"].replace_html :partial => "group_order_articles", :locals => {:order_article => @order_article}
- end
- rescue => @error
- render :update do |page|
- page['edit_box'].replace_html :partial => 'edit_order_article'
- end
- end
- end
-
- def destroy_order_article
- order_article = OrderArticle.find(params[:id])
- order_article.destroy
- # Updates ordergroup values
- order_article.group_order_articles.each { |goa| goa.group_order.update_price! }
-
- render :update do |page|
- page["order_article_#{order_article.id}"].remove
- page["group_order_articles_#{order_article.id}"].remove
- page["summary"].replace_html :partial => 'summary', :locals => {:order => order_article.order}
- page["summary"].visual_effect :highlight, :duration => 2
- end
- end
-
- def new_group_order_article
- goa = OrderArticle.find(params[:id]).group_order_articles.build
- render :update do |page|
- page["edit_box"].replace_html :partial => "new_group_order_article",
- :locals => {:group_order_article => goa}
- page["edit_box"].show
- end
- end
-
- # Creates a new GroupOrderArticle
- # If the the chosen Ordergroup hasn't ordered yet, a GroupOrder will also be created
- #FIXME: Clean up this messy code !
- def create_group_order_article
- goa = GroupOrderArticle.new(params[:group_order_article])
- order_article = goa.order_article
- order = order_article.order
-
- # creates a new GroupOrder if necessary
- group_order = GroupOrder.first :conditions => {:order_id => order.id, :ordergroup_id => goa.ordergroup_id}
- unless group_order
- goa.create_group_order(:order_id => order.id, :ordergroup_id => goa.ordergroup_id)
- else
- goa.group_order = group_order
- end
-
- # If there is an GroupOrderArticle already, only update result attribute.
- if group_order_article = GroupOrderArticle.first(:conditions => {:group_order_id => goa.group_order, :order_article_id => goa.order_article})
- goa = group_order_article
- goa.result = params[:group_order_article]["result"]
- end
-
- render :update do |page|
- if goa.save
- goa.group_order.update_price! # Update the price attribute of new GroupOrder
- order_article.update_results! if order_article.article.is_a?(StockArticle) # Update units_to_order of order_article
- page["edit_box"].hide
- page["order_article_#{order_article.id}"].replace_html :partial => 'order_article', :locals => {:order_article => order_article}
-
- page["group_order_articles_#{order_article.id}"].replace_html :partial => 'group_order_articles',
- :locals => {:order_article => order_article}
- page["group_order_article_#{goa.id}"].visual_effect :highlight, :duration => 2
-
- page["summary"].replace_html :partial => 'summary', :locals => {:order => order}
- page["order_profit"].visual_effect :highlight, :duration => 2
- else
- page["edit_box"].replace_html :partial => "new_group_order_article",
- :locals => {:group_order_article => goa}
- end
- end
- end
-
- def edit_group_order_article
- group_order_article = GroupOrderArticle.find(params[:id])
- render :partial => 'edit_group_order_article',
- :locals => {:group_order_article => group_order_article}
- end
-
- def update_group_order_article
- goa = GroupOrderArticle.find(params[:id])
-
- render :update do |page|
- if goa.update_attributes(params[:group_order_article])
- goa.group_order.update_price! # Update the price attribute of new GroupOrder
- goa.order_article.update_results! if goa.order_article.article.is_a?(StockArticle) # Update units_to_order of order_article
-
- page["edit_box"].hide
- page["order_article_#{goa.order_article.id}"].replace_html :partial => 'order_article', :locals => {:order_article => goa.order_article}
- page["group_order_articles_#{goa.order_article.id}"].replace_html :partial => 'group_order_articles',
- :locals => {:order_article => goa.order_article}
- page["summary"].replace_html :partial => 'summary', :locals => {:order => goa.order_article.order}
- page["order_profit"].visual_effect :highlight, :duration => 2
- else
- page["edit_box"].replace_html :partial => 'edit_group_order_article'
- end
- end
- end
-
- def update_group_order_article_result
- goa = GroupOrderArticle.find(params[:id])
-
- if params[:modifier] == '-'
- goa.update_attributes({:result => goa.result - 1})
- elsif params[:modifier] == '+'
- goa.update_attributes({:result => goa.result + 1})
- end
-
- render :update do |page|
- goa.group_order.update_price! # Update the price attribute of new GroupOrder
- goa.order_article.update_results! if goa.order_article.article.is_a?(StockArticle) # Update units_to_order of order_article
-
- page["order_article_#{goa.order_article.id}"].replace_html :partial => 'order_article', :locals => {:order_article => goa.order_article}
- page["group_order_articles_#{goa.order_article.id}"].replace_html :partial => 'group_order_articles',
- :locals => {:order_article => goa.order_article}
- page["summary"].replace_html :partial => 'summary', :locals => {:order => goa.order_article.order}
- page["order_profit"].visual_effect :highlight, :duration => 2
- end
-
- end
-
- def destroy_group_order_article
- goa = GroupOrderArticle.find(params[:id])
- goa.destroy
- goa.group_order.update_price! # Updates the price attribute of new GroupOrder
- goa.order_article.update_results! if goa.order_article.article.is_a?(StockArticle) # Update units_to_order of order_article
-
- render :update do |page|
- page["edit_box"].hide
- page["order_article_#{goa.order_article.id}"].replace_html :partial => 'order_article', :locals => {:order_article => goa.order_article}
- page["group_order_articles_#{goa.order_article.id}"].replace_html :partial => 'group_order_articles',
- :locals => {:order_article => goa.order_article}
- page["summary"].replace_html :partial => 'summary', :locals => {:order => goa.order_article.order}
- page["order_profit"].visual_effect :highlight, :duration => 2
+ render :action => :edit_note, :layout => false
end
end
@@ -289,27 +56,20 @@ class Finance::BalancingController < ApplicationController
# Balances the Order, Update of the Ordergroup.account_balances
def close
@order = Order.find(params[:id])
- begin
- @order.close!(@current_user)
- flash[:notice] = "Bestellung wurde erfolgreich abgerechnet, die Kontostände aktualisiert."
- redirect_to :action => "index"
- rescue => e
- flash[:error] = "Ein Fehler ist beim Abrechnen aufgetreten: " + e
- redirect_to :action => "new", :id => @order
- end
+ @order.close!(@current_user)
+ redirect_to finance_order_index_url, notice: t('finance.balancing.close.notice')
+
+ rescue => error
+ redirect_to new_finance_order_url(order_id: @order.id), alert: t('finance.balancing.close.alert', message: error.message)
end
# Close the order directly, without automaticly updating ordergroups account balances
def close_direct
@order = Order.find(params[:id])
- if @order.finished?
- @order.update_attributes(:state => 'closed', :updated_by => @current_user)
- flash[:notice] = 'Die Bestellung wurde auf "gebucht" gesetzt.'
- redirect_to :action => 'listOrders', :id => @order
- else
- flash[:error] = 'Die Bestellung ist noch nicht beendet.'
- redirect_to :action => 'listOrders', :id => @order
- end
+ @order.close_direct!(@current_user)
+ redirect_to finance_order_index_url, notice: t('finance.balancing.close_direct.notice')
+ rescue => error
+ redirect_to finance_order_index_url, alert: t('finance.balancing.close_direct.alert', message: error.message)
end
end
diff --git a/app/controllers/finance/base_controller.rb b/app/controllers/finance/base_controller.rb
new file mode 100644
index 00000000..706965c1
--- /dev/null
+++ b/app/controllers/finance/base_controller.rb
@@ -0,0 +1,11 @@
+class Finance::BaseController < ApplicationController
+ before_filter :authenticate_finance
+
+ def index
+ @financial_transactions = FinancialTransaction.order('created_on DESC').limit(8)
+ @orders = Order.finished_not_closed
+ @unpaid_invoices = Invoice.unpaid
+
+ render template: 'finance/index'
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/finance/financial_transactions_controller.rb b/app/controllers/finance/financial_transactions_controller.rb
new file mode 100644
index 00000000..a129a49d
--- /dev/null
+++ b/app/controllers/finance/financial_transactions_controller.rb
@@ -0,0 +1,65 @@
+# encoding: utf-8
+class Finance::FinancialTransactionsController < ApplicationController
+ before_filter :authenticate_finance
+ before_filter :find_ordergroup, :except => [:new_collection, :create_collection]
+ inherit_resources
+# belongs_to :ordergroup
+
+ def index
+ if params['sort']
+ sort = case params['sort']
+ when "date" then "created_on"
+ when "note" then "note"
+ when "amount" then "amount"
+ when "date_reverse" then "created_on DESC"
+ when "note_reverse" then "note DESC"
+ when "amount_reverse" then "amount DESC"
+ end
+ else
+ sort = "created_on DESC"
+ end
+
+ @financial_transactions = @ordergroup.financial_transactions.includes(:user).order(sort).
+ page(params[:page]).per(@per_page)
+ if params[:query].present?
+ @financial_transactions = @financial_transactions.where('note LIKE ?', "%#{params[:query]}%")
+ end
+ end
+
+ def new
+ @financial_transaction = @ordergroup.financial_transactions.build
+ end
+
+ def create
+ @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')
+ rescue ActiveRecord::RecordInvalid => error
+ flash.now[:alert] = error.message
+ render :action => :new
+ end
+
+ def new_collection
+ end
+
+ def create_collection
+ raise "Notiz wird benötigt!" 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')
+ rescue => error
+ redirect_to finance_new_transaction_collection_url, alert: t('finance.create_collection.create.alert', error: error.to_s)
+ end
+
+ protected
+
+ def find_ordergroup
+ @ordergroup = Ordergroup.find(params[:ordergroup_id])
+ end
+
+end
diff --git a/app/controllers/finance/group_order_articles_controller.rb b/app/controllers/finance/group_order_articles_controller.rb
new file mode 100644
index 00000000..705e2b2f
--- /dev/null
+++ b/app/controllers/finance/group_order_articles_controller.rb
@@ -0,0 +1,83 @@
+class Finance::GroupOrderArticlesController < ApplicationController
+
+ before_filter :authenticate_finance
+
+ layout false # We only use this controller to server js snippets, no need for layout rendering
+
+ def new
+ @order_article = OrderArticle.find(params[:order_article_id])
+ @group_order_article = GroupOrderArticle.new(order_article: @order_article)
+ end
+
+ def create
+ @group_order_article = GroupOrderArticle.new(params[:group_order_article])
+ @order_article = @group_order_article.order_article
+
+ # As we hide group_order_articles with a result of 0, we should not complain, when an existing group_order_article is found
+ goa = GroupOrderArticle.where(group_order_id: @group_order_article.group_order_id,
+ order_article_id: @order_article.id).first
+
+ if goa and goa.update_attributes(params[:group_order_article])
+ @group_order_article = goa
+
+ update_summaries(@group_order_article)
+ render :update
+
+ elsif @group_order_article.save
+ update_summaries(@group_order_article)
+ render :update
+
+ else # Validation failed, show form
+ render :new
+ end
+ end
+
+ def edit
+ @group_order_article = GroupOrderArticle.find(params[:id])
+ @order_article = @group_order_article.order_article
+ end
+
+ def update
+ @group_order_article = GroupOrderArticle.find(params[:id])
+ @order_article = @group_order_article.order_article
+
+ if @group_order_article.update_attributes(params[:group_order_article])
+ update_summaries(@group_order_article)
+ else
+ render :edit
+ end
+ end
+
+ def update_result
+ group_order_article = GroupOrderArticle.find(params[:id])
+ @order_article = group_order_article.order_article
+
+ if params[:modifier] == '-'
+ group_order_article.update_attribute :result, group_order_article.result - 1
+ elsif params[:modifier] == '+'
+ group_order_article.update_attribute :result, group_order_article.result + 1
+ end
+
+ update_summaries(group_order_article)
+
+ render :update
+ end
+
+ def destroy
+ group_order_article = GroupOrderArticle.find(params[:id])
+ group_order_article.destroy
+ update_summaries(group_order_article)
+ @order_article = group_order_article.order_article
+
+ render :update
+ end
+
+ protected
+
+ def update_summaries(group_order_article)
+ # Update the price attribute of new GroupOrder
+ group_order_article.group_order.update_price!
+ # Update units_to_order of order_article
+ group_order_article.order_article.update_results! if group_order_article.order_article.article.is_a?(StockArticle)
+ end
+end
diff --git a/app/controllers/finance/invoices_controller.rb b/app/controllers/finance/invoices_controller.rb
index d4f4a145..37cf839f 100644
--- a/app/controllers/finance/invoices_controller.rb
+++ b/app/controllers/finance/invoices_controller.rb
@@ -1,47 +1,31 @@
class Finance::InvoicesController < ApplicationController
def index
- @invoices = Invoice.find(:all, :order => "date DESC")
-
- respond_to do |format|
- format.html # index.html.erb
- format.xml { render :xml => @invoices }
- end
+ @invoices = Invoice.includes(:supplier, :delivery, :order).order('date DESC').page(params[:page]).per(@per_page)
end
def show
@invoice = Invoice.find(params[:id])
-
- respond_to do |format|
- format.html # show.html.erb
- format.xml { render :xml => @invoice }
- end
end
def new
@invoice = Invoice.new :supplier_id => params[:supplier_id],
- :delivery_id => params[:delivery_id], :order_id => params[:order_id]
-
- respond_to do |format|
- format.html # new.html.erb
- format.xml { render :xml => @invoice }
- end
+ :delivery_id => params[:delivery_id],
+ :order_id => params[:order_id]
end
def edit
@invoice = Invoice.find(params[:id])
end
- # POST /invoices
- # POST /invoices.xml
def create
@invoice = Invoice.new(params[:invoice])
if @invoice.save
- flash[:notice] = "Rechnung wurde erstellt."
+ flash[:notice] = I18n.t('finance.create.notice')
if @invoice.order
# Redirect to balancing page
- redirect_to :controller => 'balancing', :action => 'new', :id => @invoice.order
+ redirect_to new_finance_order_url(order_id: @invoice.order.id)
else
redirect_to [:finance, @invoice]
end
@@ -50,32 +34,20 @@ class Finance::InvoicesController < ApplicationController
end
end
- # PUT /invoices/1
- # PUT /invoices/1.xml
def update
@invoice = Invoice.find(params[:id])
- respond_to do |format|
- if @invoice.update_attributes(params[:invoice])
- flash[:notice] = 'Invoice was successfully updated.'
- format.html { redirect_to([:finance, @invoice]) }
- format.xml { head :ok }
- else
- format.html { render :action => "edit" }
- format.xml { render :xml => @invoice.errors, :status => :unprocessable_entity }
- end
+ if @invoice.update_attributes(params[:invoice])
+ redirect_to [:finance, @invoice], notice: I18n.t('finance.update.notice')
+ else
+ render :edit
end
end
- # DELETE /invoices/1
- # DELETE /invoices/1.xml
def destroy
@invoice = Invoice.find(params[:id])
@invoice.destroy
- respond_to do |format|
- format.html { redirect_to(finance_invoices_path) }
- format.xml { head :ok }
- end
+ redirect_to finance_invoices_url
end
end
diff --git a/app/controllers/finance/order_articles_controller.rb b/app/controllers/finance/order_articles_controller.rb
new file mode 100644
index 00000000..edd0fd82
--- /dev/null
+++ b/app/controllers/finance/order_articles_controller.rb
@@ -0,0 +1,39 @@
+class Finance::OrderArticlesController < ApplicationController
+
+ before_filter :authenticate_finance
+
+ layout false # We only use this controller to serve js snippets, no need for layout rendering
+
+ def new
+ @order = Order.find(params[:order_id])
+ @order_article = @order.order_articles.build
+ end
+
+ def create
+ @order = Order.find(params[:order_id])
+ @order_article = @order.order_articles.build(params[:order_article])
+ unless @order_article.save
+ render action: :new
+ end
+ end
+
+ def edit
+ @order = Order.find(params[:order_id])
+ @order_article = OrderArticle.find(params[:id])
+ end
+
+ def update
+ @order = Order.find(params[:order_id])
+ @order_article = OrderArticle.find(params[:id])
+ begin
+ @order_article.update_article_and_price!(params[:order_article], params[:article], params[:article_price])
+ rescue
+ render action: :edit
+ end
+ end
+
+ def destroy
+ @order_article = OrderArticle.find(params[:id])
+ @order_article.destroy
+ end
+end
diff --git a/app/controllers/finance/ordergroups_controller.rb b/app/controllers/finance/ordergroups_controller.rb
new file mode 100644
index 00000000..d4daeff6
--- /dev/null
+++ b/app/controllers/finance/ordergroups_controller.rb
@@ -0,0 +1,20 @@
+class Finance::OrdergroupsController < Finance::BaseController
+
+ def index
+ if params["sort"]
+ sort = case params["sort"]
+ when "name" then "name"
+ when "account_balance" then "account_balance"
+ when "name_reverse" then "name DESC"
+ when "account_balance_reverse" then "account_balance DESC"
+ end
+ else
+ sort = "name"
+ end
+
+ @ordergroups = Ordergroup.undeleted.order(sort)
+ @ordergroups = @ordergroups.where('name LIKE ?', "%#{params[:query]}%") unless params[:query].nil?
+
+ @ordergroups = @ordergroups.page(params[:page]).per(@per_page)
+ end
+end
diff --git a/app/controllers/finance/transactions_controller.rb b/app/controllers/finance/transactions_controller.rb
deleted file mode 100644
index 91380ade..00000000
--- a/app/controllers/finance/transactions_controller.rb
+++ /dev/null
@@ -1,103 +0,0 @@
-class Finance::TransactionsController < ApplicationController
- before_filter :authenticate_finance
-
- def index
- if (params[:per_page] && params[:per_page].to_i > 0 && params[:per_page].to_i <= 100)
- @per_page = params[:per_page].to_i
- else
- @per_page = 20
- end
- if params["sort"]
- sort = case params["sort"]
- when "name" then "name"
- when "account_balance" then "account_balance"
- when "name_reverse" then "name DESC"
- when "account_balance_reverse" then "account_balance DESC"
- end
- else
- sort = "name"
- end
-
- conditions = "name LIKE '%#{params[:query]}%'" unless params[:query].nil?
-
- @total = Ordergroup.without_deleted.count(:conditions => conditions)
- @groups = Ordergroup.without_deleted.paginate :conditions => conditions,
- :page => params[:page], :per_page => @per_page, :order => sort
-
- respond_to do |format|
- format.html
- format.js { render :partial => "ordergroups" }
- end
- end
-
- def list
- @group = Ordergroup.find(params[:id])
-
- if params['sort']
- sort = case params['sort']
- when "date" then "created_on"
- when "note" then "note"
- when "amount" then "amount"
- when "date_reverse" then "created_on DESC"
- when "note_reverse" then "note DESC"
- when "amount_reverse" then "amount DESC"
- end
- else
- sort = "created_on DESC"
- end
-
- conditions = ["note LIKE ?", "%#{params[:query]}%"] unless params[:query].nil?
-
- @total = @group.financial_transactions.count(:conditions => conditions)
- @financial_transactions = @group.financial_transactions.paginate(
- :page => params[:page],
- :per_page => 10,
- :conditions => conditions,
- :order => sort)
-
- respond_to do |format|
- format.html
- format.js { render :partial => "list" }
- end
- end
-
- def new
- @group = Ordergroup.find(params[:id])
- @financial_transaction = @group.financial_transactions.build
- end
-
- def create
- @group = Ordergroup.find(params[:financial_transaction][:ordergroup_id])
- amount = params[:financial_transaction][:amount]
- note = params[:financial_transaction][:note]
- begin
- @group.add_financial_transaction(amount, note, @current_user)
- flash[:notice] = 'Transaktion erfolgreich angelegt.'
- redirect_to :action => 'list', :id => @group
- rescue => e
- @financial_transaction = FinancialTransaction.new(params[:financial_transaction])
- flash.now[:error] = 'Transaktion konnte nicht angelegt werden!' + ' (' + e.message + ')'
- render :action => 'new'
- end
- end
-
- def new_collection
- end
-
- def create_collection
- note = params[:note]
- raise "Notiz wird benötigt!" if 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], note, @current_user
- end
- end
- flash[:notice] = "Alle Transaktionen wurden gespeichert."
- redirect_to :action => 'index'
- rescue => error
- flash[:error] = "Ein Fehler ist aufgetreten: " + error.to_s
- redirect_to :action => 'new_collection'
- end
-
-end
diff --git a/app/controllers/foodcoop/ordergroups_controller.rb b/app/controllers/foodcoop/ordergroups_controller.rb
index 19ccae3f..5391b798 100644
--- a/app/controllers/foodcoop/ordergroups_controller.rb
+++ b/app/controllers/foodcoop/ordergroups_controller.rb
@@ -1,29 +1,21 @@
class Foodcoop::OrdergroupsController < ApplicationController
def index
- if (params[:per_page] && params[:per_page].to_i > 0 && params[:per_page].to_i <= 100)
- @per_page = params[:per_page].to_i
- else
- @per_page = 20
+ @ordergroups = Ordergroup.undeleted.order('name DESC')
+
+ unless params[:name].blank? # Search by name
+ @ordergroups = @ordergroups.where('name LIKE ?', "%#{params[:name]}%")
end
- if (params[:only_active].to_i == 1)
- if (! params[:query].blank?)
- conditions = ["orders.starts >= ? AND name LIKE ?", Time.now.months_ago(3), "%#{params[:query]}%"]
- else
- conditions = ["orders.starts >= ?", Time.now.months_ago(3)]
- end
- else
- # if somebody uses the search field:
- conditions = ["name LIKE ?", "%#{params[:query]}%"] unless params[:query].blank?
+ if params[:only_active] # Select only active groups
+ @ordergroups = @ordergroups.joins(:orders).where("orders.starts >= ?", Time.now.months_ago(3)).uniq
end
- @total = Ordergroup.count(:conditions => conditions, :include => "orders")
- @ordergroups = Ordergroup.paginate(:page => params[:page], :per_page => @per_page, :conditions => conditions, :order => "name", :include => "orders")
+ @ordergroups = @ordergroups.page(params[:page]).per(@per_page)
respond_to do |format|
format.html # index.html.erb
- format.js { render :partial => "ordergroups" }
+ format.js { render :layout => false }
end
end
end
diff --git a/app/controllers/foodcoop/users_controller.rb b/app/controllers/foodcoop/users_controller.rb
index 046df8df..f73147bc 100644
--- a/app/controllers/foodcoop/users_controller.rb
+++ b/app/controllers/foodcoop/users_controller.rb
@@ -1,36 +1,23 @@
class Foodcoop::UsersController < ApplicationController
def index
- # sort by ordergroups
- if params[:sort_by_ordergroups]
- @users = []
- Ordergroup.find(:all, :order => "name").each do |group|
- group.users.each do |user|
- @users << user
- end
- end
- @total = @users.size
- else
- # sort by nick, thats default
- if (params[:per_page] && params[:per_page].to_i > 0 && params[:per_page].to_i <= 100)
- @per_page = params[:per_page].to_i
- else
- @per_page = 20
- end
+ @users = User.order('nick ASC')
- # if somebody uses the search field:
- unless params[:query].blank?
- conditions = ["first_name LIKE ? OR last_name LIKE ? OR nick LIKE ?",
- "%#{params[:query]}%", "%#{params[:query]}%", "%#{params[:query]}%"]
- end
+ # if somebody uses the search field:
+ unless params[:user_name].blank?
+ @users = @users.where("first_name LIKE :user_name OR last_name LIKE :user_name OR nick LIKE :user_name",
+ user_name: "%#{params[:user_name]}%")
+ end
- @total = User.count(:conditions => conditions)
- @users = User.paginate(:page => params[:page], :per_page => @per_page, :conditions => conditions, :order => "nick", :include => :groups)
+ if params[:ordergroup_name]
+ @users = @users.joins(:groups).where("groups.type = 'Ordergroup' AND groups.name LIKE ?", "%#{params[:ordergroup_name]}%")
+ end
- respond_to do |format|
- format.html # index.html.erb
- format.js { render :partial => "users" }
- end
+ @users = @users.page(params[:page]).per(@per_page).order('users.nick ASC')
+
+ respond_to do |format|
+ format.html # index.html.haml
+ format.js { render :layout => false } # index.js.erb
end
end
diff --git a/app/controllers/foodcoop/workgroups_controller.rb b/app/controllers/foodcoop/workgroups_controller.rb
index 8bbd88ae..cad728e4 100644
--- a/app/controllers/foodcoop/workgroups_controller.rb
+++ b/app/controllers/foodcoop/workgroups_controller.rb
@@ -14,13 +14,9 @@ class Foodcoop::WorkgroupsController < ApplicationController
def update
@workgroup = Workgroup.find(params[:id])
if @workgroup.update_attributes(params[:workgroup])
- flash[:notice] = "Arbeitsgruppe wurde aktualisiert"
- redirect_to foodcoop_workgroups_url
+ redirect_to foodcoop_workgroups_url, :notice => I18n.t('workgroups.update.notice')
else
render :action => 'edit'
end
end
-
- def memberships
- end
end
diff --git a/app/controllers/group_orders_controller.rb b/app/controllers/group_orders_controller.rb
new file mode 100644
index 00000000..f93e98ec
--- /dev/null
+++ b/app/controllers/group_orders_controller.rb
@@ -0,0 +1,99 @@
+# Controller for all ordering-actions that are performed by a user who is member of an Ordergroup.
+# Management actions that require the "orders" role are handled by the OrdersController.
+class GroupOrdersController < ApplicationController
+ # Security
+ before_filter :ensure_ordergroup_member
+ before_filter :ensure_open_order, :only => [:new, :create, :edit, :update, :order, :stock_order, :saveOrder]
+ before_filter :ensure_my_group_order, only: [:show, :edit, :update]
+ before_filter :enough_apples?, only: [:new, :create]
+
+ # Index page.
+ def index
+ end
+
+ def new
+ @group_order = @order.group_orders.build(:ordergroup => @ordergroup, :updated_by => current_user)
+ @ordering_data = @group_order.load_data
+ end
+
+ def create
+ @group_order = GroupOrder.new(params[:group_order])
+ begin
+ @group_order.save_ordering!
+ redirect_to group_order_url(@group_order), :notice => I18n.t('group_orders.create.notice')
+ rescue ActiveRecord::StaleObjectError
+ redirect_to group_orders_url, :alert => I18n.t('group_orders.create.error_stale')
+ rescue => exception
+ logger.error('Failed to update order: ' + exception.message)
+ redirect_to group_orders_url, :alert => I18n.t('group_orders.create.error_general')
+ end
+ end
+
+ def show
+ @order= @group_order.order
+ end
+
+ def edit
+ @ordering_data = @group_order.load_data
+ end
+
+ def update
+ @group_order.attributes = params[:group_order]
+ begin
+ @group_order.save_ordering!
+ redirect_to group_order_url(@group_order), :notice => I18n.t('group_orders.update.notice')
+ rescue ActiveRecord::StaleObjectError
+ redirect_to group_orders_url, :alert => I18n.t('group_orders.update.error_stale')
+ rescue => exception
+ logger.error('Failed to update order: ' + exception.message)
+ redirect_to group_orders_url, :alert => I18n.t('group_orders.update.error_general')
+ end
+ end
+
+ # Shows all Orders of the Ordergroup
+ # if selected, it shows all orders of the foodcoop
+ def archive
+ # get only orders belonging to the ordergroup
+ @closed_orders = Order.closed.page(params[:page]).per(10)
+
+ respond_to do |format|
+ format.html # archive.html.haml
+ format.js # archive.js.erb
+ end
+ end
+
+ private
+
+ # Returns true if @current_user is member of an Ordergroup.
+ # Used as a :before_filter by OrderingController.
+ def ensure_ordergroup_member
+ @ordergroup = @current_user.ordergroup
+ if @ordergroup.nil?
+ redirect_to root_url, :alert => I18n.t('group_orders.errors.no_member')
+ end
+ end
+
+ def ensure_open_order
+ @order = Order.find((params[:order_id] || params[:group_order][:order_id]),
+ :include => [:supplier, :order_articles])
+ unless @order.open?
+ flash[:notice] = I18n.t('group_orders.error_closed')
+ redirect_to :action => 'index'
+ end
+ end
+
+ def ensure_my_group_order
+ @group_order = @ordergroup.group_orders.find(params[:id])
+ rescue ActiveRecord::RecordNotFound
+ redirect_to group_orders_url, alert: I18n.t('group_orders.errors.notfound')
+ end
+
+ def enough_apples?
+ if @ordergroup.not_enough_apples?
+ redirect_to group_orders_url,
+ alert: t('not_enough_apples', scope: 'group_orders.messages', apples: @ordergroup.apples,
+ stop_ordering_under: FoodsoftConfig[:stop_ordering_under])
+ end
+ end
+
+end
diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb
index 1dff00c4..55afb7b2 100644
--- a/app/controllers/home_controller.rb
+++ b/app/controllers/home_controller.rb
@@ -1,34 +1,24 @@
+# encoding: utf-8
class HomeController < ApplicationController
- helper :messages
-
+
def index
- @currentOrders = Order.open
- @ordergroup = @current_user.ordergroup
# unaccepted tasks
- @unaccepted_tasks = @current_user.unaccepted_tasks
+ @unaccepted_tasks = Task.unaccepted_tasks_for(current_user)
# task in next week
- @next_tasks = @current_user.next_tasks
- @messages = Message.public.all :order => 'created_at DESC', :limit => 5
+ @next_tasks = Task.next_assigned_tasks_for(current_user)
# count tasks with no responsible person
# tasks for groups the current user is not a member are ignored
- tasks = Task.find(:all, :conditions => ["assigned = ? and done = ?", false, false])
- @unassigned_tasks_number = 0
- for task in tasks
- (@unassigned_tasks_number += 1) unless task.workgroup && !current_user.member_of?(task.workgroup)
- end
+ @unassigned_tasks = Task.unassigned_tasks_for(current_user)
end
def profile
- @user = @current_user
end
def update_profile
- @user = @current_user
- if @user.update_attributes(params[:user])
- flash[:notice] = 'Änderungen wurden gespeichert.'
- redirect_to :action => 'profile'
+ if @current_user.update_attributes(params[:user])
+ redirect_to my_profile_url, notice: I18n.t('home.changes_saved')
else
- render :action => 'profile'
+ render :profile
end
end
@@ -37,10 +27,6 @@ class HomeController < ApplicationController
@ordergroup = @user.ordergroup
unless @ordergroup.nil?
- @ordergroup_column_names = ["Description", "Actual Size", "Balance", "Updated"]
- @ordergroup_columns = ["description", "account_balance", "account_updated"]
-
- #listing the financial transactions with ajax...
if params['sort']
sort = case params['sort']
@@ -55,21 +41,11 @@ class HomeController < ApplicationController
sort = "created_on DESC"
end
- # or if somebody uses the search field:
- conditions = ["note LIKE ?", "%#{params[:query]}%"] unless params[:query].nil?
+ @financial_transactions = @ordergroup.financial_transactions.page(params[:page]).per(@per_page).order(sort)
+ @financial_transactions = @financial_transactions.where("note LIKE ?", "%#{params[:query]}%") if params[:query].present?
- @total = @ordergroup.financial_transactions.count(:conditions => conditions)
- @financial_transactions = @ordergroup.financial_transactions.paginate(:page => params[:page],
- :per_page => 10,
- :conditions => conditions,
- :order => sort)
- respond_to do |format|
- format.html # myOrdergroup.haml
- format.js { render :partial => "finance/transactions/list" }
- end
else
- flash[:error] = "Leider bist Du kein Mitglied einer Bestellgruppe"
- redirect_to root_path
+ redirect_to root_path, :alert => I18n.t('home.no_ordergroups')
end
end
@@ -78,9 +54,9 @@ class HomeController < ApplicationController
membership = Membership.find(params[:membership_id])
if membership.user == current_user
membership.destroy
- flash[:notice] = "Du bist jetzt kein Mitglied der Gruppe #{membership.group.name} mehr."
+ flash[:notice] = I18n.t('home.ordergroup_cancelled', :group => membership.group.name)
else
- flash[:error] = "Ein Problem ist aufgetreten."
+ flash[:error] = I18n.t('errors.general')
end
redirect_to my_profile_path
end
diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb
index d4ef712d..f301156a 100644
--- a/app/controllers/invites_controller.rb
+++ b/app/controllers/invites_controller.rb
@@ -1,26 +1,26 @@
class InvitesController < ApplicationController
before_filter :authenticate_membership_or_admin, :only => [:new]
- #TODO: auhtorize also for create action.
+ #TODO: authorize also for create action.
def new
@invite = Invite.new(:user => @current_user, :group => @group)
-
- render :update do |page|
- page.replace_html :edit_box, :partial => "new"
- page.show :edit_box
- end
end
def create
@invite = Invite.new(params[:invite])
+ if @invite.save
+ Mailer.invite(@invite).deliver
- render :update do |page|
- if @invite.save
- page.replace_html :edit_box, :partial => "success"
- else
- page.replace_html :edit_box, :partial => "new"
+ respond_to do |format|
+ format.html do
+ redirect_to back_or_default_path, notice: I18n.t('invites.success')
+ end
+ format.js { render layout: false }
end
+
+ else
+ render action: :new
end
end
end
diff --git a/app/controllers/login_controller.rb b/app/controllers/login_controller.rb
index e3388311..745d5e58 100644
--- a/app/controllers/login_controller.rb
+++ b/app/controllers/login_controller.rb
@@ -1,69 +1,33 @@
+# encoding: utf-8
class LoginController < ApplicationController
skip_before_filter :authenticate # no authentication since this is the login page
- before_filter :validate_token, :only => [:password, :update_password]
+ before_filter :validate_token, :only => [:new_password, :update_password]
- verify :method => :post, :only => [:login, :reset_password, :new], :redirect_to => { :action => :index }
-
- # Redirects to the login action.
- def index
- render :action => 'login'
- end
-
- # Logout the current user and deletes the session
- def logout
- self.return_to = nil
- current_user = nil
- reset_session
- flash[:notice] = "Abgemeldet"
- render :action => 'login'
- end
-
- # Displays a "denied due to insufficient privileges" message and provides the login form.
- def denied
- flash[:error] = "Du bist nicht berechtigt diese Seite zu besuchen. Bitte als berechtige Benutzerin anmelden oder zurück gehen."
- render :action => 'login'
- end
-
- # Login to the foodsoft.
- def login
- user = User.find_by_nick(params[:login][:user])
- if user && user.has_password(params[:login][:password])
- # Set last_login to Now()
- user.update_attribute(:last_login, Time.now)
- self.current_user = user
- if (redirect = return_to)
- self.return_to = nil
- redirect_to redirect
- else
- redirect_to root_path
- end
- else
- current_user = nil
- flash[:error] = "Tschuldige, die Anmeldung war nicht erfolgreich. Bitte erneut versuchen."
- end
- end
-
# Display the form to enter an email address requesting a token to set a new password.
def forgot_password
+ @user = User.new
end
# Sends an email to a user with the token that allows setting a new password through action "password".
def reset_password
- if (user = User.find_by_email(params[:login][:email]))
+ if request.get? || params[:user].nil? # Catch for get request and give better error message.
+ redirect_to forgot_password_url, alert: 'Ein Problem ist aufgetreten. Bitte erneut versuchen' and return
+ end
+
+ if (user = User.find_by_email(params[:user][:email]))
user.reset_password_token = user.new_random_password(16)
user.reset_password_expires = Time.now.advance(:days => 2)
if user.save
- email = Mailer.deliver_reset_password(user)
+ Mailer.reset_password(user).deliver
logger.debug("Sent password reset email to #{user.email}.")
end
end
- flash[:notice] = "Wenn Deine E-Mail hier registiert ist bekommst Du jetzt eine Nachricht mit einem Passwort-Zurücksetzen-Link."
- render :action => 'login'
+ redirect_to login_url, :notice => I18n.t('login.controller.reset_password.notice')
end
# Set a new password with a token from the password reminder email.
# Called with params :id => User.id and :token => User.reset_password_token to specify a new password.
- def password
+ def new_password
end
# Sets a new password.
@@ -74,38 +38,32 @@ class LoginController < ApplicationController
@user.reset_password_token = nil
@user.reset_password_expires = nil
@user.save
- flash[:notice] = "Dein Passwort wurde aktualisiert. Du kannst Dich jetzt anmelden."
- render :action => 'login'
+ redirect_to login_url, :notice => I18n.t('login.controller.update_password.notice')
else
- render :action => 'password'
+ render :new_password
end
end
- # Invited users.
- def invite
- @invite = Invite.find_by_token(params[:id])
- if (@invite.nil? || @invite.expires_at < Time.now)
- flash[:error] = "Deine Einladung ist nicht (mehr) gültig."
- render :action => 'login'
+ # For invited users.
+ def accept_invitation
+ @invite = Invite.find_by_token(params[:token])
+ if @invite.nil? || @invite.expires_at < Time.now
+ redirect_to login_url, alert: I18n.t('login.controller.error_invite_invalid')
elsif @invite.group.nil?
- flash[:error] = "Die Gruppe, in die Du eingeladen wurdest, existiert leider nicht mehr."
- render :action => 'login'
- elsif (request.post?)
+ redirect_to login_url, alert: I18n.t('login.controller.error_group_invalid')
+ elsif request.post?
User.transaction do
@user = User.new(params[:user])
@user.email = @invite.email
if @user.save
Membership.new(:user => @user, :group => @invite.group).save!
@invite.destroy
- flash[:notice] = "Herzlichen Glückwunsch, Dein Account wurde erstellt. Du kannst Dich nun einloggen."
- render :action => 'login'
+ redirect_to login_url, notice: I18n.t('login.controller.accept_invitation.notice')
end
end
else
@user = User.new(:email => @invite.email)
end
- rescue
- flash[:error] = "Ein Fehler ist aufgetreten. Bitte erneut versuchen."
end
protected
@@ -113,8 +71,7 @@ class LoginController < ApplicationController
def validate_token
@user = User.find_by_id_and_reset_password_token(params[:id], params[:token])
if (@user.nil? || @user.reset_password_expires < Time.now)
- flash[:error] = "Ungültiger oder abgelaufener Token. Bitte versuch es erneut."
- render :action => 'forgot_password'
+ redirect_to forgot_password_url, alert: I18n.t('login.controller.error_token_invalid')
end
end
end
diff --git a/app/controllers/messages_controller.rb b/app/controllers/messages_controller.rb
index 8e5f38e1..9a713dd9 100644
--- a/app/controllers/messages_controller.rb
+++ b/app/controllers/messages_controller.rb
@@ -1,76 +1,34 @@
class MessagesController < ApplicationController
-
+
# Renders the "inbox" action.
def index
- @messages = Message.public.paginate :page => params[:page], :per_page => 20, :order => 'created_at DESC'
+ @messages = Message.public.page(params[:page]).per(@per_page).order('created_at DESC').includes(:sender)
end
-
+
# Creates a new message object.
def new
- @message = Message.new
+ @message = Message.new(params[:message])
+ if @message.reply_to and not @message.reply_to.is_readable_for?(current_user)
+ redirect_to new_message_url, alert: 'Nachricht ist privat!'
+ end
end
-
+
# Creates a new message.
def create
@message = @current_user.send_messages.new(params[:message])
if @message.save
- #FIXME: Send Mails wit ID instead of using message.state ...
- call_rake :send_emails
- flash[:notice] = "Nachricht ist gespeichert und wird versendet."
- redirect_to messages_path
+ Resque.enqueue(UserNotifier, FoodsoftConfig.scope, 'message_deliver', @message.id)
+ redirect_to messages_url, :notice => I18n.t('messages.create.notice')
else
render :action => 'new'
end
end
-
+
# Shows a single message.
def show
@message = Message.find(params[:id])
- end
-
- # Replys to the message specified through :id.
- def reply
- message = Message.find(params[:id])
- @message = Message.new(:recipient => message.sender, :subject => "Re: #{message.subject}")
- @message.body = "#{message.sender.nick} schrieb am #{I18n.l(message.created_at.to_date)} um #{I18n.l(message.created_at, :format => :time)}:\n"
- message.body.each_line{|l| @message.body += "> #{l}"}
- render :action => 'new'
- end
-
- # Shows new-message form with the recipient user specified through :id.
- def user
- if (recipient = User.find(params[:id]))
- @message = Message.new(:recipient => recipient)
- render :action => 'new'
- else
- flash[:error] = 'Unbekannte_r EmpfängerIn.'
- redirect_to :action=> 'index'
+ unless @message.is_readable_for?(current_user)
+ redirect_to messages_url, alert: 'Nachricht ist privat!'
end
end
-
- # Shows new-message form with the recipient user specified through :id.
- def group
- group = Group.find(params[:id], :include => :memberships)
- if (group && !group.memberships.empty?)
- @message = Message.new(:group_id => group.id)
- render :action => 'new'
- else
- flash[:error] = 'Empfängergruppe ist unbekannt oder hat keine Mitglieder.'
- redirect_to :action=> 'index'
- end
- end
-
- # Auto-complete for recipient user list.
- def auto_complete_for_message_recipients_nicks
- @users = User.find(:all,
- :conditions => ['LOWER(nick) LIKE ?', '%' + params[:message][:recipients_nicks].downcase + '%'],
- :order => :nick, :limit => 8)
- render :partial => '/shared/auto_complete_users'
- end
-
- # Returns list of all users as auto-completion hint.
- def user_list
- @users = User.find(:all, :order => :nick)
- render :partial => '/shared/auto_complete_users'
- end
end
diff --git a/app/controllers/order_comments_controller.rb b/app/controllers/order_comments_controller.rb
new file mode 100644
index 00000000..a047dc3a
--- /dev/null
+++ b/app/controllers/order_comments_controller.rb
@@ -0,0 +1,16 @@
+class OrderCommentsController < ApplicationController
+
+ def new
+ @order = Order.find(params[:order_id])
+ @order_comment = @order.comments.build(:user => current_user)
+ end
+
+ def create
+ @order_comment = OrderComment.new(params[:order_comment])
+ if @order_comment.save
+ render :layout => false
+ else
+ render :action => :new, :layout => false
+ end
+ end
+end
diff --git a/app/controllers/ordering_controller.rb b/app/controllers/ordering_controller.rb
deleted file mode 100644
index 87283011..00000000
--- a/app/controllers/ordering_controller.rb
+++ /dev/null
@@ -1,209 +0,0 @@
-# Controller for all ordering-actions that are performed by a user who is member of an Ordergroup.
-# Management actions that require the "orders" role are handled by the OrdersController.
-class OrderingController < ApplicationController
- # Security
- before_filter :ensure_ordergroup_member
- before_filter :ensure_open_order, :only => [:order, :stock_order, :saveOrder]
-
- verify :method => :post, :only => [:saveOrder], :redirect_to => {:action => :index}
-
- # Index page.
- def index
- end
-
- # Edit a current order.
- def order
- redirect_to :action => 'stock_order', :id => @order if @order.stockit?
-
- # Load order article data...
- @articles_grouped_by_category = @order.articles_grouped_by_category
- # save results of earlier orders in array
- ordered_articles = Array.new
- @group_order = @order.group_orders.find(:first,
- :conditions => "ordergroup_id = #{@ordergroup.id}", :include => :group_order_articles)
-
- if @group_order
- # Group has already ordered, so get the results...
- for goa in @group_order.group_order_articles
- ordered_articles[goa.order_article_id] = {:quantity => goa.quantity,
- :tolerance => goa.tolerance,
- :quantity_result => goa.result(:quantity),
- :tolerance_result => goa.result(:tolerance)}
- end
- @version = @group_order.lock_version
- @availableFunds = @ordergroup.get_available_funds(@group_order)
- else
- @version = 0
- @availableFunds = @ordergroup.get_available_funds
- end
-
- # load prices ....
- @price = Array.new; @unit = Array.new;
- @others_quantity = Array.new; @quantity = Array.new; @quantity_result = Array.new; @used_quantity = Array.new; @unused_quantity = Array.new
- @others_tolerance = Array.new; @tolerance = Array.new; @tolerance_result = Array.new; @used_tolerance = Array.new; @unused_tolerance = Array.new
- i = 0;
- @articles_grouped_by_category.each do |category_name, order_articles|
- for order_article in order_articles
- # price/unit size
- @price[i] = order_article.article.fc_price
- @unit[i] = order_article.article.unit_quantity
- # quantity
- @quantity[i] = (ordered_articles[order_article.id] ? ordered_articles[order_article.id][:quantity] : 0)
- @others_quantity[i] = order_article.quantity - @quantity[i]
- @used_quantity[i] = (ordered_articles[order_article.id] ? ordered_articles[order_article.id][:quantity_result] : 0)
- # tolerance
- @tolerance[i] = (ordered_articles[order_article.id] ? ordered_articles[order_article.id][:tolerance] : 0)
- @others_tolerance[i] = order_article.tolerance - @tolerance[i]
- @used_tolerance[i] = (ordered_articles[order_article.id] ? ordered_articles[order_article.id][:tolerance_result] : 0)
- i += 1
- end
- end
- end
-
- def stock_order
- # Load order article data...
- @articles_grouped_by_category = @order.articles_grouped_by_category
- # save results of earlier orders in array
- ordered_articles = Array.new
- @group_order = @order.group_orders.find(:first,
- :conditions => "ordergroup_id = #{@ordergroup.id}", :include => :group_order_articles)
-
- if @group_order
- # Group has already ordered, so get the results...
- for goa in @group_order.group_order_articles
- ordered_articles[goa.order_article_id] = {:quantity => goa.quantity,
- :tolerance => goa.tolerance,
- :quantity_result => goa.result(:quantity),
- :tolerance_result => goa.result(:tolerance)}
- end
- @version = @group_order.lock_version
- @availableFunds = @ordergroup.get_available_funds(@group_order)
- else
- @version = 0
- @availableFunds = @ordergroup.get_available_funds
- end
-
- # load prices ....
- @price = Array.new; @quantity_available = Array.new
- @others_quantity = Array.new; @quantity = Array.new; @quantity_result = Array.new; @used_quantity = Array.new; @unused_quantity = Array.new
- i = 0;
- @articles_grouped_by_category.each do |category_name, order_articles|
- for order_article in order_articles
- # price/unit size
- @price[i] = order_article.article.fc_price
- @quantity_available[i] = order_article.article.quantity_available(@order)
- # quantity
- @quantity[i] = (ordered_articles[order_article.id] ? ordered_articles[order_article.id][:quantity] : 0)
- @others_quantity[i] = order_article.quantity - @quantity[i]
- @used_quantity[i] = (ordered_articles[order_article.id] ? ordered_articles[order_article.id][:quantity_result] : 0)
- i += 1
- end
- end
- end
-
- # Update changes to a current order.
- def saveOrder
- if (params[:total_balance].to_i < 0) #TODO: Better use a real test on sufficiant funds
- flash[:error] = 'Der Bestellwert übersteigt das verfügbare Guthaben.'
- redirect_to :action => 'order'
- elsif (ordered = params[:ordered])
- begin
- Order.transaction do
- # Try to find group_order
- group_order = @order.group_orders.first :conditions => "ordergroup_id = #{@ordergroup.id}",
- :include => [:group_order_articles]
- # Create group order if necessary...
- unless group_order.nil?
- # check for conflicts well ahead
- if (params[:version].to_i != group_order.lock_version)
- raise ActiveRecord::StaleObjectError
- end
- else
- group_order = @ordergroup.group_orders.create!(:order => @order, :updated_by => @current_user, :price => 0)
- end
-
- # Create/update group_order_articles...
- for order_article in @order.order_articles
-
- # Find the group_order_article, create a new one if necessary...
- group_order_article = group_order.group_order_articles.detect { |v| v.order_article_id == order_article.id }
- if group_order_article.nil?
- group_order_article = group_order.group_order_articles.create(:order_article_id => order_article.id)
- end
-
- # Get ordered quantities and update group_order_articles/_quantities...
- quantities = ordered.fetch(order_article.id.to_s, {:quantity => 0, :tolerance => 0})
- group_order_article.update_quantities(quantities[:quantity].to_i, quantities[:tolerance].to_i)
-
- # Also update results for the order_article
- order_article.update_results!
- end
-
- group_order.update_price!
- group_order.update_attribute(:updated_by, @current_user)
- end
- flash[:notice] = 'Die Bestellung wurde gespeichert.'
- rescue ActiveRecord::StaleObjectError
- flash[:error] = 'In der Zwischenzeit hat jemand anderes auch bestellt, daher konnte die Bestellung nicht aktualisiert werden.'
- rescue => exception
- logger.error('Failed to update order: ' + exception.message)
- flash[:error] = 'Die Bestellung konnte nicht aktualisiert werden, da ein Fehler auftrat.'
- end
- redirect_to :action => 'my_order_result', :id => @order
- end
- end
-
- # Shows the Result for the Ordergroup the current user belongs to
- # this method decides between finished and unfinished orders
- def my_order_result
- @order= Order.find(params[:id])
- @group_order = @order.group_order(@ordergroup)
- end
-
- # Shows all Orders of the Ordergroup
- # if selected, it shows all orders of the foodcoop
- def myOrders
- # get only orders belonging to the ordergroup
- @closed_orders = Order.paginate :page => params[:page], :per_page => 10,
- :conditions => { :state => 'closed' }, :order => "orders.ends DESC"
-
- respond_to do |format|
- format.html # myOrders.haml
- format.js { render :partial => "orders", :locals => {:orders => @closed_orders, :pagination => true} }
- end
- end
-
- # adds a Comment to the Order
- def add_comment
- order = Order.find(params[:id])
- comment = order.comments.build(params[:comment])
- comment.user = @current_user
- if !comment.text.blank? and comment.save
- flash[:notice] = "Kommentar wurde erstellt."
- else
- flash[:error] = "Kommentar konnte nicht erstellt werden. Leerer Kommentar?"
- end
- redirect_to :action => 'my_order_result', :id => order
- end
-
- private
-
- # Returns true if @current_user is member of an Ordergroup.
- # Used as a :before_filter by OrderingController.
- def ensure_ordergroup_member
- @ordergroup = @current_user.ordergroup
- if @ordergroup.nil?
- flash[:notice] = 'Sie gehören keiner Bestellgruppe an.'
- redirect_to :controller => root_path
- end
- end
-
- def ensure_open_order
- @order = Order.find(params[:id], :include => [:supplier, :order_articles])
- unless @order.open?
- flash[:notice] = 'Diese Bestellung ist bereits abgeschlossen.'
- redirect_to :action => 'index'
- end
- end
-
-end
diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb
index 053a0646..7fba518a 100644
--- a/app/controllers/orders_controller.rb
+++ b/app/controllers/orders_controller.rb
@@ -1,13 +1,11 @@
+# encoding: utf-8
+#
# Controller for managing orders, i.e. all actions that require the "orders" role.
# Normal ordering actions of members of order groups is handled by the OrderingController.
class OrdersController < ApplicationController
before_filter :authenticate_orders
- # Define layout exceptions for PDF actions:
- layout "application", :except => [:faxPdf, :matrixPdf, :articlesPdf, :groupsPdf]
- prawnto :prawn => { :page_size => 'A4' }
-
# List orders
def index
@open_orders = Order.open
@@ -22,18 +20,7 @@ class OrdersController < ApplicationController
else
sort = "ends DESC"
end
- @orders = Order.paginate :page => params[:page], :per_page => @per_page,
- :order => sort, :conditions => "state != 'open'",
- :include => :supplier
-
- respond_to do |format|
- format.html
- format.js do
- render :update do |page|
- page.replace_html 'orders_table', :partial => "orders"
- end
- end
- end
+ @orders = Order.page(params[:page]).per(@per_page).order(sort).where("state != 'open'").includes(:supplier)
end
# Gives a view for the results to a specific order
@@ -41,13 +28,26 @@ class OrdersController < ApplicationController
def show
@order= Order.find(params[:id])
- if params[:view] # Articles-list will be replaced
- partial = case params[:view]
- when 'normal' then "articles"
- when 'groups'then 'shared/articles_by_groups'
- when 'articles'then 'shared/articles_by_articles'
+ respond_to do |format|
+ format.html
+ format.js do
+ @partial = case params[:view]
+ when 'default' then "articles"
+ when 'groups'then 'shared/articles_by_groups'
+ when 'articles'then 'shared/articles_by_articles'
+ else 'articles'
+ end
+ render :layout => false
+ end
+ format.pdf do
+ pdf = case params[:document]
+ when 'groups' then OrderByGroups.new(@order)
+ when 'articles' then OrderByArticles.new(@order)
+ when 'fax' then OrderFax.new(@order)
+ when 'matrix' then OrderMatrix.new(@order)
+ end
+ send_data pdf.to_pdf, filename: pdf.filename, type: 'application/pdf'
end
- render :partial => partial, :locals => {:order => @order} if partial
end
end
@@ -60,10 +60,12 @@ class OrdersController < ApplicationController
# order_articles will be saved in Order.article_ids=()
def create
@order = Order.new(params[:order])
+ @order.created_by = current_user
if @order.save
- flash[:notice] = "Die Bestellung wurde erstellt."
+ flash[:notice] = I18n.t('orders.create.notice')
redirect_to @order
else
+ logger.debug "[debug] order errors: #{@order.errors.messages}"
render :action => 'new'
end
end
@@ -78,7 +80,7 @@ class OrdersController < ApplicationController
def update
@order = Order.find params[:id]
if @order.update_attributes params[:order]
- flash[:notice] = "Die Bestellung wurde aktualisiert."
+ flash[:notice] = I18n.t('orders.update.notice')
redirect_to :action => 'show', :id => @order
else
render :action => 'edit'
@@ -95,31 +97,7 @@ class OrdersController < ApplicationController
def finish
order = Order.find(params[:id])
order.finish!(@current_user)
- call_rake "foodsoft:finished_order_tasks", :order_id => order.id
- flash[:notice] = "Die Bestellung wurde beendet."
- redirect_to order
- end
-
- # Renders the groups-orderd PDF.
- def groupsPdf
- @order = Order.find(params[:id])
- prawnto :filename => "#{Date.today}_#{@order.name}_GruppenSortierung.pdf"
- end
-
- # Renders the articles-orderd PDF.
- def articlesPdf
- @order = Order.find(params[:id])
- prawnto :filename => "#{Date.today}_#{@order.name}_ArtikelSortierung.pdf",
- :prawn => { :left_margin => 48,
- :right_margin => 48,
- :top_margin => 48,
- :bottom_margin => 48 }
- end
-
- # Renders the fax PDF.
- def faxPdf
- @order = Order.find(params[:id])
- prawnto :filename => "#{Date.today}_#{@order.name}_FAX.pdf"
+ redirect_to order, notice: I18n.t('orders.finish.notice')
end
# Renders the fax-text-file
@@ -127,15 +105,15 @@ class OrdersController < ApplicationController
def text_fax_template
order = Order.find(params[:id])
supplier = order.supplier
- contact = Foodsoft.config[:contact].symbolize_keys
- text = "Bestellung für" + " #{Foodsoft.config[:name]}"
- text += "\n" + "Kundennummer" + ": #{supplier.customer_number}" unless supplier.customer_number.blank?
- text += "\n" + "Liefertag" + ": "
- text += "\n\n#{supplier.name}\n#{supplier.address}\nFAX: #{supplier.fax}\n\n"
- text += "****** " + "Versandadresse" + "\n\n"
- text += "#{Foodsoft.config[:name]}\n#{contact[:street]}\n#{contact[:zip_code]} #{contact[:city]}\n\n"
- text += "****** " + "Artikel" + "\n\n"
- text += "Nummer" + " " + "Menge" + " " + "Name" + "\n"
+ 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" + 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 += "****** " + 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"
+ text += I18n.t('orders.fax.number') + " " + I18n.t('orders.fax.amount') + " " + I18n.t('orders.fax.name') + "\n"
# now display all ordered articles
order.order_articles.ordered.all(:include => [:article, :article_price]).each do |oa|
number = oa.article.order_number
@@ -148,28 +126,4 @@ class OrdersController < ApplicationController
:type => 'text/plain; charset=utf-8; header=present',
:disposition => "attachment; filename=#{order.name}"
end
-
- # Renders the matrix PDF.
- def matrixPdf
- @order = Order.find(params[:id])
- unless @order.order_articles.ordered.empty?
- prawnto :filename => "#{Date.today}_#{@order.name}_Matrix.pdf"
- else
- flash[:error] = "Es sind keine Artikel bestellt worden."
- redirect_to @order
- end
- end
-
- # adds a Comment to the Order
- def add_comment
- order = Order.find(params[:id])
- comment = order.comments.build(params[:comment])
- comment.user = @current_user
- if !comment.text.empty? and comment.save
- flash[:notice] = "Kommentar wurde erstellt."
- else
- flash[:error] = "Kommentar konnte nicht erstellt werden. Leerer Kommentar?"
- end
- redirect_to order
- end
end
diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb
index 78c65144..e2190159 100644
--- a/app/controllers/pages_controller.rb
+++ b/app/controllers/pages_controller.rb
@@ -1,3 +1,4 @@
+# encoding: utf-8
class PagesController < ApplicationController
def index
@@ -16,7 +17,7 @@ class PagesController < ApplicationController
elsif params[:id]
page = Page.find_by_id(params[:id])
if page.nil?
- flash[:error] = "Seite existiert nicht!"
+ flash[:error] = I18n.t('pages.cshow.error_noexist')
redirect_to all_pages_path and return
else
redirect_to wiki_page_path(page.permalink) and return
@@ -28,7 +29,7 @@ class PagesController < ApplicationController
elsif @page.redirect?
page = Page.find_by_id(@page.redirect)
unless page.nil?
- flash[:notice] = "Weitergeleitet von #{@page.title} ..."
+ flash[:notice] = I18n.t('pages.cshow.redirect_notice', :page => @page.title)
redirect_to wiki_page_path(page.permalink)
end
end
@@ -56,7 +57,7 @@ class PagesController < ApplicationController
render :action => 'new'
else
if @page.save
- flash[:notice] = 'Seite wurde angelegt.'
+ flash[:notice] = I18n.t('pages.create.notice')
redirect_to(wiki_page_path(@page.permalink))
else
render :action => "new"
@@ -75,7 +76,7 @@ class PagesController < ApplicationController
if @page.save
@page.parent_id = parent_id if (!params[:parent_id].blank? \
and params[:parent_id] != @page_id)
- flash[:notice] = 'Seite wurde aktualisiert.'
+ flash[:notice] = I18n.t('pages.update.notice')
redirect_to wiki_page_path(@page.permalink)
else
render :action => "edit"
@@ -83,7 +84,7 @@ class PagesController < ApplicationController
end
rescue ActiveRecord::StaleObjectError
- flash[:error] = "Achtung, die Seite wurde gerade von jemand anderes bearbeitet. Bitte versuche es erneut."
+ flash[:error] = I18n.t('pages.error_stale_object')
redirect_to wiki_page_path(@page.permalink)
end
@@ -91,25 +92,27 @@ class PagesController < ApplicationController
@page = Page.find(params[:id])
@page.destroy
- flash[:notice] = "Die Seite '#{@page.title}' und alle Unterseiten wurden erfolgreich gelöscht."
+ flash[:notice] = I18n.t('pages.destroy.notice', :page => @page.title)
redirect_to wiki_path
end
def all
- @recent_pages = Page.non_redirected.all :order => 'updated_at DESC'
- @pages = Page.non_redirected.all :order => 'title'
- @top_pages = Page.no_parent.non_redirected.all :order => 'created_at'
+ @pages = Page.non_redirected
+ @partial = params[:view] || 'recent_changes'
- view = params[:view]
- params[:view] = nil
-
- case view
- when 'recentChanges'
- render :partial => 'recent_changes' and return
- when 'siteMap'
- render :partial => 'site_map' and return
- when 'titleList'
- render :partial => 'title_list' and return
+ if params[:name]
+ @pages = @pages.where("title LIKE ?", "%#{params[:name]}%").limit(20).order('updated_at DESC')
+ @partial = 'title_list'
+ else
+ order = case @partial
+ when 'recent_changes' then
+ 'updated_at DESC'
+ when 'site_map' then
+ 'created_at DESC'
+ when 'title_list' then
+ 'title DESC'
+ end
+ @pages.order(order)
end
end
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
new file mode 100644
index 00000000..c89b818d
--- /dev/null
+++ b/app/controllers/sessions_controller.rb
@@ -0,0 +1,31 @@
+class SessionsController < ApplicationController
+
+ skip_before_filter :authenticate
+ layout 'login'
+
+ def new
+ end
+
+ def create
+ user = User.authenticate(params[:nick], params[:password])
+ if user
+ session[:user_id] = user.id
+ session[:scope] = FoodsoftConfig.scope # Save scope in session to not allow switching between foodcoops with one account
+ if session[:return_to].present?
+ redirect_to_url = session[:return_to]
+ session[:return_to] = nil
+ else
+ redirect_to_url = root_url
+ end
+ redirect_to redirect_to_url, :notice => I18n.t('sessions.logged_in')
+ else
+ flash.now.alert = I18n.t('sessions.login_invalid')
+ render "new"
+ end
+ end
+
+ def destroy
+ session[:user_id] = nil
+ redirect_to login_url, :notice => I18n.t('sessions.logged_out')
+ end
+end
diff --git a/app/controllers/stock_takings_controller.rb b/app/controllers/stock_takings_controller.rb
index 4b6004cf..8d45e0fd 100644
--- a/app/controllers/stock_takings_controller.rb
+++ b/app/controllers/stock_takings_controller.rb
@@ -1,76 +1,21 @@
class StockTakingsController < ApplicationController
+ inherit_resources
def index
- @stock_takings = StockTaking.find(:all)
-
- respond_to do |format|
- format.html # index.html.erb
- format.xml { render :xml => @stock_takings }
- end
- end
-
- def show
- @stock_taking = StockTaking.find(params[:id])
-
- respond_to do |format|
- format.html # show.html.erb
- format.xml { render :xml => @stock_taking }
- end
+ @stock_takings = StockTaking.order('date DESC').page(params[:page]).per(@per_page)
end
def new
@stock_taking = StockTaking.new
- StockArticle.without_deleted.each { |a| @stock_taking.stock_changes.build(:stock_article => a) }
-
- respond_to do |format|
- format.html # new.html.erb
- format.xml { render :xml => @stock_taking }
- end
- end
-
-
- def edit
- @stock_taking = StockTaking.find(params[:id])
+ StockArticle.undeleted.each { |a| @stock_taking.stock_changes.build(:stock_article => a) }
end
def create
- @stock_taking = StockTaking.new(params[:stock_taking])
-
- respond_to do |format|
- if @stock_taking.save
- flash[:notice] = 'StockTaking was successfully created.'
- format.html { redirect_to(@stock_taking) }
- format.xml { render :xml => @stock_taking, :status => :created, :location => @stock_taking }
- else
- format.html { render :action => "new" }
- format.xml { render :xml => @stock_taking.errors, :status => :unprocessable_entity }
- end
- end
+ create!(:notice => I18n.t('stock_takings.create.notice'))
end
def update
- @stock_taking = StockTaking.find(params[:id])
-
- respond_to do |format|
- if @stock_taking.update_attributes(params[:stock_taking])
- flash[:notice] = 'StockTaking was successfully updated.'
- format.html { redirect_to(@stock_taking) }
- format.xml { head :ok }
- else
- format.html { render :action => "edit" }
- format.xml { render :xml => @stock_taking.errors, :status => :unprocessable_entity }
- end
- end
- end
-
- def destroy
- @stock_taking = StockTaking.find(params[:id])
- @stock_taking.destroy
-
- respond_to do |format|
- format.html { redirect_to(stock_takings_url) }
- format.xml { head :ok }
- end
+ update!(:notice => I18n.t('stock_takings.update.notice'))
end
def fill_new_stock_article_form
@@ -107,6 +52,4 @@ class StockTakingsController < ApplicationController
page.visual_effect :DropOut, "stock_change_#{stock_change.id}"
end
end
-
-
end
diff --git a/app/controllers/stockit_controller.rb b/app/controllers/stockit_controller.rb
index 83cf7ce1..9ee40efe 100644
--- a/app/controllers/stockit_controller.rb
+++ b/app/controllers/stockit_controller.rb
@@ -1,10 +1,8 @@
class StockitController < ApplicationController
def index
- @stock_articles = StockArticle.without_deleted.all(
- :include => [:supplier, :article_category],
- :order => 'suppliers.name, article_categories.name, articles.name'
- )
+ @stock_articles = StockArticle.undeleted.includes(:supplier, :article_category).
+ order('suppliers.name, article_categories.name, articles.name')
end
def new
@@ -14,8 +12,7 @@ class StockitController < ApplicationController
def create
@stock_article = StockArticle.new(params[:stock_article])
if @stock_article.save
- flash[:notice] = "Lagerartikel wurde gespeichert."
- redirect_to stock_articles_path
+ redirect_to stock_articles_path, :notice => I18n.t('stockit.stock_create.notice')
else
render :action => 'new'
end
@@ -28,31 +25,25 @@ class StockitController < ApplicationController
def update
@stock_article = StockArticle.find(params[:id])
if @stock_article.update_attributes(params[:stock_article])
- flash[:notice] = "Lagerartikel wurde gespeichert."
- redirect_to stock_articles_path
+ redirect_to stock_articles_path, :notice => I18n.t('stockit.stock_update.notice')
else
render :action => 'edit'
end
end
def destroy
- StockArticle.find(params[:id]).destroy
- redirect_to stock_articles_path
+ @article = StockArticle.find(params[:id])
+ @article.mark_as_deleted
+ render :layout => false
rescue => error
- flash[:error] = "Ein Fehler ist aufgetreten: " + error.message
- redirect_to stock_articles_path
+ render :partial => "destroy_fail", :layout => false,
+ :locals => { :fail_msg => I18n.t('errors.general_msg', :msg => error.message) }
end
- def auto_complete_for_article_name
- conditions = [ "LOWER(articles.name) LIKE ?", '%' + params[:article][:name].downcase + '%' ]
-
- if params[:supplier_id]
- @supplier = Supplier.find(params[:supplier_id])
- @articles = @supplier.articles.without_deleted.all(:conditions => conditions, :limit => 8)
- else
- @articles = Article.without_deleted.not_in_stock.all(:conditions => conditions, :limit => 8)
- end
- render :partial => 'shared/auto_complete_articles'
+ #TODO: Fix this!!
+ def articles_search
+ @articles = Article.not_in_stock.limit(8).where('name LIKE ?', "%#{params[:term]}%")
+ render :json => @articles.map(&:name)
end
def fill_new_stock_article_form
diff --git a/app/controllers/suppliers_controller.rb b/app/controllers/suppliers_controller.rb
index 59051536..7d234a20 100644
--- a/app/controllers/suppliers_controller.rb
+++ b/app/controllers/suppliers_controller.rb
@@ -1,9 +1,10 @@
+# encoding: utf-8
class SuppliersController < ApplicationController
before_filter :authenticate_suppliers, :except => [:index, :list]
helper :deliveries
def index
- @suppliers = Supplier.without_deleted :order => 'name'
+ @suppliers = Supplier.undeleted.order(:name)
@deliveries = Delivery.recent
end
@@ -26,7 +27,7 @@ class SuppliersController < ApplicationController
def create
@supplier = Supplier.new(params[:supplier])
if @supplier.save
- flash[:notice] = "Lieferant wurde erstellt"
+ flash[:notice] = I18n.t('suppliers.create.notice')
redirect_to suppliers_path
else
render :action => 'new'
@@ -40,7 +41,7 @@ class SuppliersController < ApplicationController
def update
@supplier = Supplier.find(params[:id])
if @supplier.update_attributes(params[:supplier])
- flash[:notice] = 'Lieferant wurde aktualisiert'
+ flash[:notice] = I18n.t('suppliers.update.notice')
redirect_to @supplier
else
render :action => 'edit'
@@ -49,11 +50,11 @@ class SuppliersController < ApplicationController
def destroy
@supplier = Supplier.find(params[:id])
- @supplier.destroy
- flash[:notice] = "Lieferant wurde gelöscht"
+ @supplier.mark_as_deleted
+ flash[:notice] = I18n.t('suppliers.destroy.notice')
redirect_to suppliers_path
rescue => e
- flash[:error] = "Ein Fehler ist aufgetreten: " + e.message
+ flash[:error] = I18n.t('errors.general_msg', :msg => e.message)
redirect_to @supplier
end
diff --git a/app/controllers/tasks_controller.rb b/app/controllers/tasks_controller.rb
index 57bff129..16fc0f73 100644
--- a/app/controllers/tasks_controller.rb
+++ b/app/controllers/tasks_controller.rb
@@ -1,29 +1,25 @@
+# encoding: utf-8
class TasksController < ApplicationController
#auto_complete_for :user, :nick
def index
- @non_group_tasks = Task.non_group
- @groups = Workgroup.all
+ @non_group_tasks = Task.non_group.includes(assignments: :user)
+ @groups = Workgroup.includes(open_tasks: {assignments: :user})
end
def user
- @unaccepted_tasks = @current_user.unaccepted_tasks
- @accepted_tasks = @current_user.accepted_tasks
+ @unaccepted_tasks = Task.unaccepted_tasks_for(current_user)
+ @accepted_tasks = Task.accepted_tasks_for(current_user)
end
def new
- @task = Task.new
+ @task = Task.new(current_user_id: current_user.id)
end
def create
@task = Task.new(params[:task])
- if @task.errors.empty? && @task.save
- flash[:notice] = "Aufgabe wurde erstellt"
- if @task.workgroup
- redirect_to :action => "workgroup", :id => @task.workgroup
- else
- redirect_to :action => "index"
- end
+ if @task.save
+ redirect_to tasks_url, :notice => I18n.t('tasks.create.notice')
else
render :template => "tasks/new"
end
@@ -35,17 +31,18 @@ class TasksController < ApplicationController
def edit
@task = Task.find(params[:id])
+ @task.current_user_id = current_user.id
end
def update
@task = Task.find(params[:id])
@task.attributes=(params[:task])
if @task.errors.empty? && @task.save
- flash[:notice] = "Aufgabe wurde aktualisiert"
+ flash[:notice] = I18n.t('tasks.update.notice')
if @task.workgroup
- redirect_to :action => "workgroup", :id => @task.workgroup
+ redirect_to workgroup_tasks_url(workgroup_id: @task.workgroup_id)
else
- redirect_to :action => "index"
+ redirect_to tasks_url
end
else
render :template => "tasks/edit"
@@ -53,18 +50,13 @@ class TasksController < ApplicationController
end
def destroy
- Task.find(params[:id]).destroy
- flash[:notice] = "Aufgabe wurde gelöscht"
- redirect_to :action => "index"
- end
-
- # Delete an given Assignment
- # currently used in edit-view
- def drop_assignment
- ass = Assignment.find(params[:id])
- task = ass.task
- ass.destroy
- redirect_to :action => "show", :id => task
+ task = Task.find(params[:id])
+ # Save user_ids to update apple statistics after destroy
+ user_ids = task.user_ids
+ task.destroy
+ task.update_ordergroup_stats(user_ids)
+
+ redirect_to tasks_url, :notice => I18n.t('tasks.destroy.notice')
end
# assign current_user to the task and set the assignment to "accepted"
@@ -76,8 +68,7 @@ class TasksController < ApplicationController
else
task.assignments.create(:user => current_user, :accepted => true)
end
- flash[:notice] = "Du hast die Aufgabe übernommen"
- redirect_to user_tasks_path
+ redirect_to user_tasks_path, :notice => I18n.t('tasks.accept.notice')
end
# deletes assignment between current_user and given task
@@ -86,34 +77,21 @@ class TasksController < ApplicationController
redirect_to :action => "index"
end
- def update_status
- Task.find(params[:id]).update_attribute("done", params[:task][:done])
- flash[:notice] = "Aufgabenstatus wurde aktualisiert"
- redirect_to :action => "index"
+ def set_done
+ Task.find(params[:id]).update_attribute :done, true
+ redirect_to tasks_url, :notice => I18n.t('tasks.set_done.notice')
end
# Shows all tasks, which are already done
def archive
- @tasks = Task.done.paginate :page => params[:page], :per_page => 30
+ @tasks = Task.done.page(params[:page]).per(@per_page).order('tasks.updated_on DESC').includes(assignments: :user)
end
# shows workgroup (normal group) to edit weekly_tasks_template
def workgroup
- @group = Group.find(params[:id])
+ @group = Group.find(params[:workgroup_id])
if @group.is_a? Ordergroup
- flash[:error] = "Keine Arbeitsgruppe gefunden"
- redirect_to :action => "index"
+ redirect_to tasks_url, :alert => I18n.t('tasks.error_not_found')
end
end
-
- # this method is uses for the auto_complete-function from script.aculo.us
- def auto_complete_for_task_user_list
- @users = User.find(
- :all,
- :conditions => [ 'LOWER(nick) LIKE ?', '%' + params[:task][:user_list].downcase + '%' ],
- :order => 'nick ASC',
- :limit => 8
- )
- render :partial => '/shared/auto_complete_users'
- end
end
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
new file mode 100644
index 00000000..916b33f7
--- /dev/null
+++ b/app/controllers/users_controller.rb
@@ -0,0 +1,11 @@
+class UsersController < ApplicationController
+
+ # Currently used to display users nick and ids for autocomplete
+ def index
+ @users = User.where("nick LIKE ?", "%#{params[:q]}%")
+ respond_to do |format|
+ format.json { render :json => @users.map { |u| u.token_attributes } }
+ end
+ end
+
+end
diff --git a/app/documents/order_by_articles.rb b/app/documents/order_by_articles.rb
new file mode 100644
index 00000000..705393f5
--- /dev/null
+++ b/app/documents/order_by_articles.rb
@@ -0,0 +1,34 @@
+# encoding: utf-8
+class OrderByArticles < OrderPdf
+
+ def filename
+ I18n.t('documents.order_by_articles.filename', :name => @order.name, :date => @order.ends.to_date) + '.pdf'
+ end
+
+ def title
+ I18n.t('documents.order_by_articles.title', :name => @order.name,
+ :date => @order.ends.strftime(I18n.t('date.formats.default')))
+ end
+
+ def body
+ @order.order_articles.ordered.each do |order_article|
+ text "#{order_article.article.name} (#{order_article.article.unit} | #{order_article.price.unit_quantity.to_s} | #{number_with_precision(order_article.price.fc_price, precision: 2)})",
+ style: :bold, size: 10
+ rows = []
+ rows << I18n.t('documents.order_by_articles.rows')
+ for goa in order_article.group_order_articles
+ rows << [goa.group_order.ordergroup.name,
+ goa.result,
+ number_with_precision(order_article.price.fc_price * goa.result, precision: 2)]
+ end
+
+ table rows, column_widths: [200,40,40], cell_style: {size: 8, overflow: :shrink_to_fit} do |table|
+ table.columns(1..2).align = :right
+ table.cells.border_width = 1
+ table.cells.border_color = '666666'
+ end
+ move_down 10
+ end
+ end
+
+end
diff --git a/app/documents/order_by_groups.rb b/app/documents/order_by_groups.rb
new file mode 100644
index 00000000..5ee66cca
--- /dev/null
+++ b/app/documents/order_by_groups.rb
@@ -0,0 +1,52 @@
+# encoding: utf-8
+class OrderByGroups < OrderPdf
+
+ def filename
+ I18n.t('documents.order_by_groups.filename', :name => @order.name, :date => @order.ends.to_date) + '.pdf'
+ end
+
+ def title
+ I18n.t('documents.order_by_groups.title', :name => @order.name,
+ :date => @order.ends.strftime(I18n.t('date.formats.default')))
+ end
+
+ def body
+ # Start rendering
+ @order.group_orders.each do |group_order|
+ text group_order.ordergroup.name, size: 9, style: :bold
+
+ total = 0
+ rows = []
+ rows << I18n.t('documents.order_by_groups.rows') # Table Header
+
+ group_order_articles = group_order.group_order_articles.ordered
+ group_order_articles.each do |goa|
+ price = goa.order_article.price.fc_price
+ sub_total = price * goa.result
+ total += sub_total
+ rows << [goa.order_article.article.name,
+ goa.result,
+ number_with_precision(price, precision: 2),
+ goa.order_article.price.unit_quantity,
+ goa.order_article.article.unit,
+ number_with_precision(sub_total, precision: 2)]
+ end
+ rows << [ I18n.t('documents.order_by_groups.sum'), nil, nil, nil, nil, number_with_precision(total, precision: 2)]
+
+ table rows, column_widths: [250,50,50,50,50,50], cell_style: {size: 8, overflow: :shrink_to_fit} do |table|
+ # borders
+ table.cells.borders = []
+ table.row(0).borders = [:bottom]
+ table.row(group_order_articles.size).borders = [:bottom]
+ table.cells.border_width = 1
+ table.cells.border_color = '666666'
+
+ table.columns(1..3).align = :right
+ table.columns(5).align = :right
+ end
+
+ move_down 15
+ end
+
+ end
+end
diff --git a/app/documents/order_fax.rb b/app/documents/order_fax.rb
new file mode 100644
index 00000000..cc86c94a
--- /dev/null
+++ b/app/documents/order_fax.rb
@@ -0,0 +1,72 @@
+# encoding: utf-8
+class OrderFax < OrderPdf
+
+ def filename
+ I18n.t('documents.order_fax.filename', :name => @order.name, :date => @order.ends.to_date) + '.pdf'
+ end
+
+ def title
+ false
+ end
+
+ def body
+ contact = FoodsoftConfig[:contact].symbolize_keys
+
+ # From paragraph
+ bounding_box [margin_box.right-200,margin_box.top], width: 200 do
+ text FoodsoftConfig[:name], size: 9, align: :right
+ move_down 5
+ text contact[:street], size: 9, align: :right
+ move_down 5
+ text "#{contact[:zip_code]} #{contact[:city]}", size: 9, align: :right
+ move_down 5
+ text "#{I18n.t('simple_form.labels.supplier.customer_number')}: #{@order.supplier.try(:customer_number)}", size: 9, align: :right
+ move_down 5
+ text "#{I18n.t('simple_form.labels.supplier.phone')}: #{contact[:phone]}", size: 9, align: :right
+ move_down 5
+ text "#{I18n.t('simple_form.labels.supplier.email')}: #{contact[:email]}", size: 9, align: :right
+ end
+
+ # Recipient
+ bounding_box [margin_box.left,margin_box.top-60], width: 200 do
+ text @order.name
+ move_down 5
+ text @order.supplier.try(:address).to_s
+ move_down 5
+ text "#{I18n.t('simple_form.labels.supplier.fax')}: #{@order.supplier.try(:fax)}"
+ end
+
+ move_down 5
+ text Date.today.strftime(I18n.t('date.formats.default')), align: :right
+
+ move_down 10
+ text "#{I18n.t('simple_form.labels.delivery.delivered_on')}:"
+ move_down 10
+ text "#{I18n.t('simple_form.labels.supplier.contact_person')}: #{@order.supplier.try(:contact_person)}"
+ move_down 10
+
+ # Articles
+ data = [I18n.t('documents.order_fax.rows')]
+ data = @order.order_articles.ordered.all(include: :article).collect do |a|
+ [a.article.order_number,
+ a.units_to_order,
+ a.article.name,
+ a.price.unit_quantity,
+ a.article.unit,
+ a.price.price]
+ end
+ table data, cell_style: {size: 8, overflow: :shrink_to_fit} do |table|
+ table.cells.border_width = 1
+ table.cells.border_color = '666666'
+
+ table.columns(1).align = :right
+ table.columns(3..5).align = :right
+ end
+ #font_size: 8,
+ #vertical_padding: 3,
+ #border_style: :grid,
+ #headers: ["BestellNr.", "Menge","Name", "Gebinde", "Einheit","Preis/Einheit"],
+ #align: {0 => :left}
+ end
+
+end
diff --git a/app/documents/order_matrix.rb b/app/documents/order_matrix.rb
new file mode 100644
index 00000000..f43d490b
--- /dev/null
+++ b/app/documents/order_matrix.rb
@@ -0,0 +1,87 @@
+# encoding: utf-8
+class OrderMatrix < OrderPdf
+
+ MAX_ARTICLES_PER_PAGE = 16 # How many order_articles shoud written on a page
+
+ def filename
+ I18n.t('documents.order_matrix.filename', :name => @order.name, :date => @order.ends.to_date) + '.pdf'
+ end
+
+ def title
+ I18n.t('documents.order_matrix.title', :name => @order.name,
+ :date => @order.ends.strftime(I18n.t('date.formats.default')))
+ end
+
+ def body
+ order_articles = @order.order_articles.ordered
+
+ text I18n.t('documents.order_matrix.heading'), style: :bold
+ move_down 5
+ text I18n.t('documents.order_matrix.total', :count => order_articles.size), size: 8
+ move_down 10
+
+ order_articles_data = [I18n.t('documents.order_matrix.rows')]
+
+ order_articles.each do |a|
+ order_articles_data << [a.article.name,
+ a.article.unit,
+ a.price.unit_quantity,
+ number_with_precision(a.price.fc_price, precision: 2),
+ a.units_to_order]
+ end
+
+ table order_articles_data, cell_style: {size: 8, overflow: :shrink_to_fit} do |table|
+ table.cells.border_width = 1
+ table.cells.border_color = '666666'
+ end
+
+ page_number = 0
+ total_num_order_articles = order_articles.size
+
+ while page_number * MAX_ARTICLES_PER_PAGE < total_num_order_articles do # Start page generating
+
+ page_number += 1
+ start_new_page(layout: :landscape)
+
+ # Collect order_articles for this page
+ current_order_articles = order_articles.select do |a|
+ order_articles.index(a) >= (page_number-1) * MAX_ARTICLES_PER_PAGE and
+ order_articles.index(a) < page_number * MAX_ARTICLES_PER_PAGE
+ end
+
+ # Make order_articles header
+ header = [""]
+ for header_article in current_order_articles
+ name = header_article.article.name.gsub(/[-\/]/, " ").gsub(".", ". ")
+ name = name.split.collect { |w| w.truncate(8) }.join(" ")
+ header << name.truncate(30)
+ end
+
+ # Collect group results
+ groups_data = [header]
+
+ @order.group_orders.includes(:ordergroup).all.each do |group_order|
+
+ group_result = [group_order.ordergroup.name.truncate(20)]
+
+ for order_article in current_order_articles
+ # get the Ordergroup result for this order_article
+ goa = order_article.group_order_articles.first conditions: { group_order_id: group_order.id }
+ group_result << ((goa.nil? || goa.result == 0) ? "" : goa.result.to_i)
+ end
+ groups_data << group_result
+ end
+
+ # Make table
+ column_widths = [85]
+ (MAX_ARTICLES_PER_PAGE + 1).times { |i| column_widths << 41 unless i == 0 }
+ table groups_data, column_widths: column_widths, cell_style: {size: 8, overflow: :shrink_to_fit} do |table|
+ table.cells.border_width = 1
+ table.cells.border_color = '666666'
+ table.row_colors = ['ffffff','ececec']
+ end
+
+ end
+ end
+
+end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index fbf40827..78a2fc40 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -1,3 +1,5 @@
+# encoding: utf-8
+#
# Methods added to this helper will be available to all templates in the application.
module ApplicationHelper
@@ -18,97 +20,76 @@ module ApplicationHelper
end
# Creates ajax-controlled-links for pagination
- # see also the plugin "will_paginate"
def pagination_links_remote(collection, options = {})
per_page = options[:per_page] || @per_page
params = options[:params] || {}
- update = options[:update] || nil
-
- # Translations
- previous_label = '« ' + "Vorherige"
- next_label = "Nächste" + ' »'
- # Merge other url-options for will_paginate
params = params.merge({:per_page => per_page})
- will_paginate collection, { :params => params, :remote => true, :update => update,
- :previous_label => previous_label, :next_label => next_label, }
+ paginate collection, :params => params, :remote => true
end
# Link-collection for per_page-options when using the pagination-plugin
def items_per_page(options = {})
per_page_options = options[:per_page_options] || [20, 50, 100]
current = options[:current] || @per_page
- action = options[:action] || controller.action_name
- update = options[:update] || nil
+ params = params || {}
- links = []
- per_page_options.each do |per_page|
- unless per_page == current
- links << link_to_remote(
- per_page,
- { :url => { :action => action, :params => {:per_page => per_page}},
- :before => "Element.show('loader')",
- :success => "Element.hide('loader')",
- :method => :get, :update => update } )
- else
- links << per_page
- end
+ links = per_page_options.map do |per_page|
+ params.merge!({:per_page => per_page})
+ link_class = 'btn'
+ link_class << ' disabled' if per_page == current
+ link_to(per_page, params, :remote => true, class: link_class)
end
- return "Pro Seite: " + links.join(" ")
+
+ content_tag :div, class: 'btn-group pull-right' do
+ links.join.html_safe
+ end
+
end
-
- def sort_td_class_helper(param)
- result = 'class="sortup"' if params[:sort] == param
- result = 'class="sortdown"' if params[:sort] == param + "_reverse"
- return result
- end
-
+
def sort_link_helper(text, key, options = {})
- per_page = options[:per_page] || 10
- action = options[:action] || "list"
+ # Hmtl options
remote = options[:remote].nil? ? true : options[:remote]
- key += "_reverse" if params[:sort] == key
-
- link_options = {
- :url => url_for(:params => params.merge({:sort => key, :page => nil, :per_page => per_page})),
- :before => "Element.show('loader')",
- :success => "Element.hide('loader')",
- :method => :get
- }
+ class_name = case params[:sort]
+ when key then
+ 'sortup'
+ when key + '_reverse' then
+ 'sortdown'
+ else
+ nil
+ end
html_options = {
- :title => _("Nach #{text} sortieren"),
- :href => url_for(:action => action, :params => params.merge({:sort => key, :page => nil, :per_page => per_page}))
+ :title => I18n.t('helpers.application.sort_by', text: text),
+ :remote => remote,
+ :class => class_name
}
- if remote
- link_to_remote(text, link_options, html_options)
- else
- link_to(text, link_options[:url], html_options)
- end
+
+ # Url options
+ key += "_reverse" if params[:sort] == key
+ per_page = options[:per_page] || @per_page
+ url_options = params.merge(per_page: per_page, sort: key)
+ url_options.merge!({page: params[:page]}) if params[:page]
+ url_options.merge!({query: params[:query]}) if params[:query]
+
+ link_to(text, url_for(url_options), html_options)
end
# Generates a link to the top of the website
def link_to_top
- link_to image_tag("arrow_up_red.png", :size => "16x16", :border => "0", :alt => "Nach oben"), "#"
+ link_to '#' do
+ content_tag :i, nil, class: 'icon-arrow-up icon-large'
+ end
end
# Returns the weekday. 0 is sunday, 1 is monday and so on
def weekday(dayNumber)
- weekdays = ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"]
+ weekdays = I18n.t('date.day_names')
return weekdays[dayNumber]
end
- # highlights a phrase in given text
- # based on the rails text-helper 'highlight'
- def highlight_phrase(text, phrase, highlighter = '\1 ')
- unless phrase.blank? || text.nil?
- phrase.split(' ').each {|keyword| text.gsub!(/(#{Regexp.escape(keyword)})/i, highlighter)}
- end
- return text
- end
-
# to set a title for both the h1-tag and the title in the header
def title(page_title, show_title = true)
- @content_for_title = page_title.to_s
+ content_for(:title) { page_title.to_s }
@show_title = show_title
end
@@ -121,8 +102,11 @@ module ApplicationHelper
end
def icon(name, options={})
- icons = { :delete => { :file => 'b_drop.png', :alt => 'Löschen'},
- :edit => { :file => 'b_edit.png', :alt => 'Bearbeiten'}}
+ icons = {
+ :delete => { :file => 'b_drop.png', :alt => I18n.t('ui.delete')},
+ :edit => { :file => 'b_edit.png', :alt => I18n.t('ui.edit')},
+ :members => { :file => 'b_users.png', :alt => I18n.t('helpers.application.edit_user')}
+ }
options[:alt] ||= icons[name][:alt]
options[:title] ||= icons[name][:title]
options.merge!({:size => '16x16',:border => "0"})
@@ -137,28 +121,42 @@ module ApplicationHelper
:success => "Element.hide('loader')",
:method => :get
}
- link_to_remote(text, remote_options.merge(options))
+ link_to(text, options[:url], remote_options.merge(options))
end
def format_roles(record)
roles = []
- roles << 'Admin' if record.role_admin?
- roles << 'Finanzen' if record.role_finance?
- roles << 'Lieferanten' if record.role_suppliers?
- roles << 'Artikel' if record.role_article_meta?
- roles << 'Bestellung' if record.role_orders?
+ roles << I18n.t('helpers.application.role_admin') if record.role_admin?
+ roles << I18n.t('helpers.application.role_finance') if record.role_finance?
+ roles << I18n.t('helpers.application.role_suppliers') if record.role_suppliers?
+ roles << I18n.t('helpers.application.role_article_meta') if record.role_article_meta?
+ roles << I18n.t('helpers.application.role_orders') if record.role_orders?
roles.join(', ')
end
def link_to_gmaps(address)
- link_to h(address), "http://maps.google.de/?q=#{h(address)}", :title => "Show it on google maps",
+ link_to h(address), "http://maps.google.com/?q=#{h(address)}", :title => I18n.t('helpers.application.show_google_maps'),
:target => "_blank"
end
# offers a link for writing message to user
# checks for nil (useful for relations)
def link_to_user_message_if_valid(user)
- user.nil? ? '??' : ( link_to user.nick, user_message_path(user), :title => _('Nachricht schreiben') )
+ user.nil? ? '??' : link_to(user.nick, new_message_path('message[mail_to]' => user.id),
+ :title => I18n.t('helpers.application.write_message'))
+ end
+
+ def bootstrap_flash
+ flash_messages = []
+ flash.each do |type, message|
+ type = :success if type == :notice
+ type = :error if type == :alert
+ text = content_tag(:div,
+ content_tag(:button, I18n.t('ui.marks.close').html_safe, :class => "close", "data-dismiss" => "alert") +
+ message, :class => "alert fade in alert-#{type}")
+ flash_messages << text if message
+ end
+ flash_messages.join("\n").html_safe
end
end
diff --git a/app/helpers/articles_helper.rb b/app/helpers/articles_helper.rb
index f6b2458f..ee8f58e1 100644
--- a/app/helpers/articles_helper.rb
+++ b/app/helpers/articles_helper.rb
@@ -6,9 +6,14 @@ module ArticlesHelper
end
def row_classes(article)
- classes = " click-me"
- classes += " unavailable" if !article.availability
- classes += " just_updated" if @article.recently_updated && @article.availability
- classes
+ classes = []
+ classes << "unavailable" if !article.availability
+ classes << "just-updated" if article.recently_updated && article.availability
+ classes.join(" ")
+ end
+
+ # Flatten search params, used in import from external database
+ def search_params
+ Hash[params[:search].map { |k,v| [k, (v.is_a?(Array) ? v.join(" ") : v)] }]
end
end
\ No newline at end of file
diff --git a/app/helpers/deliveries_helper.rb b/app/helpers/deliveries_helper.rb
index d6e9ed65..3682430e 100644
--- a/app/helpers/deliveries_helper.rb
+++ b/app/helpers/deliveries_helper.rb
@@ -3,14 +3,15 @@ module DeliveriesHelper
def link_to_invoice(delivery)
if delivery.invoice
link_to number_to_currency(delivery.invoice.amount), [:finance, delivery.invoice],
- :title => "Rechnung anzeigen"
+ title: I18n.t('helpers.deliveries.show_invoice')
else
- link_to "Rechnung anlegen", new_finance_invoice_path(:supplier_id => delivery.supplier.id, :delivery_id => delivery.id)
+ link_to I18n.t('helpers.deliveries.new_invoice'), new_finance_invoice_path(supplier_id: delivery.supplier.id, delivery_id: delivery.id),
+ class: 'btn btn-mini'
end
end
def stock_articles_for_select(supplier)
- supplier.stock_articles.without_deleted.collect {|a| ["#{a.name} (#{number_to_currency a.price}/#{a.unit})", a.id] }
+ supplier.stock_articles.undeleted.map {|a| ["#{a.name} (#{number_to_currency a.price}/#{a.unit})", a.id] }
end
end
diff --git a/app/helpers/finance/balancing_helper.rb b/app/helpers/finance/balancing_helper.rb
new file mode 100644
index 00000000..2daa44b2
--- /dev/null
+++ b/app/helpers/finance/balancing_helper.rb
@@ -0,0 +1,13 @@
+module Finance::BalancingHelper
+ def balancing_view_partial
+ view = params[:view] || 'edit_results'
+ case view
+ when 'edit_results' then
+ 'edit_results_by_articles'
+ when 'groups_overview' then
+ 'shared/articles_by_groups'
+ when 'articles_overview' then
+ 'shared/articles_by_articles'
+ end
+ end
+end
diff --git a/app/helpers/finance/order_articles_helper.rb b/app/helpers/finance/order_articles_helper.rb
new file mode 100644
index 00000000..548dfc4f
--- /dev/null
+++ b/app/helpers/finance/order_articles_helper.rb
@@ -0,0 +1,10 @@
+module Finance::OrderArticlesHelper
+
+ def new_order_articles_collection
+ if @order.stockit?
+ StockArticle.order('articles.name')
+ else
+ @order.supplier.articles.order('articles.name')
+ end
+ end
+end
diff --git a/app/helpers/finance/ordergroups_helper.rb b/app/helpers/finance/ordergroups_helper.rb
new file mode 100644
index 00000000..65ddd6f2
--- /dev/null
+++ b/app/helpers/finance/ordergroups_helper.rb
@@ -0,0 +1,2 @@
+module Finance::OrdergroupsHelper
+end
diff --git a/app/helpers/group_orders_helper.rb b/app/helpers/group_orders_helper.rb
new file mode 100644
index 00000000..b7707744
--- /dev/null
+++ b/app/helpers/group_orders_helper.rb
@@ -0,0 +1,39 @@
+module GroupOrdersHelper
+ def data_to_js(ordering_data)
+ ordering_data[:order_articles].map { |id, data|
+ [id, data[:price], data[:unit], data[:total_price], data[:others_quantity], data[:others_tolerance], data[:used_quantity], data[:quantity_available]]
+ }.map { |row|
+ "addData(#{row.join(', ')});"
+ }.join("\n")
+ end
+
+ def link_to_ordering(order, options = {})
+ path = if group_order = order.group_order(current_user.ordergroup)
+ edit_group_order_path(group_order, :order_id => order.id)
+ else
+ new_group_order_path(:order_id => order.id)
+ end
+ link_to order.name, path, options
+ end
+
+ # Return css class names for order result table
+
+ def order_article_class_name(quantity, tolerance, result)
+ if (quantity + tolerance > 0)
+ result > 0 ? 'success' : 'failed'
+ else
+ 'ignored'
+ end
+ end
+
+ def get_order_results(order_article, group_order_id)
+ goa = order_article.group_order_articles.detect { |goa| goa.group_order_id == group_order_id }
+ quantity, tolerance, result, sub_total = if goa.present?
+ [goa.quantity, goa.tolerance, goa.result, goa.total_price(order_article)]
+ else
+ [0, 0, 0, 0]
+ end
+
+ {group_order_article: goa, quantity: quantity, tolerance: tolerance, result: result, sub_total: sub_total}
+ end
+end
\ No newline at end of file
diff --git a/app/helpers/messages_helper.rb b/app/helpers/messages_helper.rb
index 1ced0806..31836ecb 100644
--- a/app/helpers/messages_helper.rb
+++ b/app/helpers/messages_helper.rb
@@ -1,16 +1,4 @@
module MessagesHelper
- def groups_for_select
- groups = [[" -- Arbeitsgruppen -- ", ""]]
- groups += Workgroup.find(:all, :order => 'name', :include => :memberships).reject{ |g| g.memberships.empty? }.collect do |g|
- [g.name, g.id]
- end
- groups += [[" -- Bestellgruppen -- ", ""]]
- groups += Ordergroup.without_deleted(:order => 'name', :include => :memberships).reject{ |g| g.memberships.empty? }.collect do |g|
- [g.name, g.id]
- end
- groups
- end
-
def format_subject(message, length)
if message.subject.length > length
subject = truncate(message.subject, :length => length)
@@ -19,6 +7,14 @@ module MessagesHelper
subject = message.subject
body = truncate(message.body, :length => length - subject.length)
end
- "#{link_to(h(subject), message)} #{h(body)} "
+ "#{link_to(h(subject), message)} #{h(body)} ".html_safe
+ end
+
+ def link_to_new_message(options = {})
+ messages_params = options[:message_params] || nil
+ link_text = content_tag :id, nil, class: 'icon-envelope'
+ link_text << " #{options[:text]}" if options[:text].present?
+ link_to(link_text.html_safe, new_message_path(message: messages_params), class: 'btn',
+ title: I18n.t('helpers.submit.message.create'))
end
end
diff --git a/app/helpers/order_comments_helper.rb b/app/helpers/order_comments_helper.rb
new file mode 100644
index 00000000..dfa87c2a
--- /dev/null
+++ b/app/helpers/order_comments_helper.rb
@@ -0,0 +1,2 @@
+module OrderCommentsHelper
+end
diff --git a/app/helpers/orders_helper.rb b/app/helpers/orders_helper.rb
index ffb2e4c2..9ddcca4a 100644
--- a/app/helpers/orders_helper.rb
+++ b/app/helpers/orders_helper.rb
@@ -1,19 +1,18 @@
+# encoding: utf-8
module OrdersHelper
def update_articles_link(order, text, view)
- link_to_remote text, :url => order_path(order, :view => view),
- :update => 'articles', :before => "Element.show('loader')", :success => "Element.hide('loader')",
- :method => :get
+ link_to text, order_path(order, view: view), remote: true
end
- def link_to_pdf(order, action)
- link_to image_tag("save_pdf.png", :size => "16x16", :border => "0", :alt => "PDF erstellen"),
- { :action => action, :id => order, :format => :pdf }, { :title => "PDF erstellen" }
+ def order_pdf(order, document, text)
+ link_to text, order_path(order, document: document, format: :pdf), title: I18n.t('helpers.orders.order_pdf')
end
def options_for_suppliers_to_select
- suppliers = Supplier.without_deleted.collect {|s| [ s.name, url_for(:action => "new", :supplier_id => s)] }
- stockit = [["Lager", url_for(:action => 'new', :supplier_id => 0)]]
- options_for_select(stockit + suppliers)
+ options = [[I18n.t('helpers.orders.option_choose')]]
+ options += Supplier.all.map {|s| [ s.name, url_for(action: "new", supplier_id: s)] }
+ options += [[I18n.t('helpers.orders.option_stock'), url_for(action: 'new', supplier_id: 0)]]
+ options_for_select(options)
end
end
diff --git a/app/helpers/pages_helper.rb b/app/helpers/pages_helper.rb
index 51c5a253..09be29f0 100644
--- a/app/helpers/pages_helper.rb
+++ b/app/helpers/pages_helper.rb
@@ -2,14 +2,14 @@ module PagesHelper
include WikiCloth
def wikified_body(body, title = nil)
- WikiCloth.new({:data => body+"\n", :link_handler => Wikilink.new, :params => {:referer => title}}).to_html
+ WikiCloth.new({:data => body+"\n", :link_handler => Wikilink.new, :params => {:referer => title}}).to_html.html_safe
end
def link_to_wikipage(page, text = nil)
if text == nil
- link_to page.title, wiki_page_path(page.permalink)
+ link_to page.title, wiki_page_path(:permalink => page.permalink)
else
- link_to text, wiki_page_path(page.permalink)
+ link_to text, wiki_page_path(:permalink => page.permalink)
end
end
@@ -41,11 +41,11 @@ module PagesHelper
unless toc.blank?
toc = WikiCloth.new({:data => toc, :link_handler => Wikilink.new}).to_html
- section_count = 0
toc.gsub(/
([^<>\n]*)/) do
- section_count += 1
- " #{$1} "
- end
+ name = $1
+ anchor = name.gsub(/\s/, '_').gsub(/[^a-zA-Z_]/, '')
+ "#{name.truncate(20)} "
+ end.html_safe
end
end
diff --git a/app/helpers/sessions_helper.rb b/app/helpers/sessions_helper.rb
new file mode 100644
index 00000000..309f8b2e
--- /dev/null
+++ b/app/helpers/sessions_helper.rb
@@ -0,0 +1,2 @@
+module SessionsHelper
+end
diff --git a/app/helpers/stockit_helper.rb b/app/helpers/stockit_helper.rb
index 8a34e11d..2888603c 100644
--- a/app/helpers/stockit_helper.rb
+++ b/app/helpers/stockit_helper.rb
@@ -1,2 +1,7 @@
module StockitHelper
+ def stock_article_classes(article)
+ class_names = []
+ class_names << "unavailable" if article.quantity_available <= 0
+ class_names.join(" ")
+ end
end
diff --git a/app/helpers/tasks_helper.rb b/app/helpers/tasks_helper.rb
index dc597bc2..c123c9ae 100644
--- a/app/helpers/tasks_helper.rb
+++ b/app/helpers/tasks_helper.rb
@@ -1,10 +1,16 @@
module TasksHelper
-
+
+ def task_assignments(task)
+ task.assignments.map do |ass|
+ content_tag :span, ass.user.nick, :class => (ass.accepted? ? 'accepted' : 'unaccepted')
+ end.join(", ").html_safe
+ end
+
# generate colored number of still required users
def highlighted_required_users(task)
unless task.enough_users_assigned?
- still_required = task.required_users - task.assignments.select { |ass| ass.accepted }.size
- "(#{still_required}) "
+ content_tag :span, task.still_required_users, class: 'badge badge-important',
+ title: I18n.t('helpers.tasks.required_users', :count => task.still_required_users)
end
end
end
diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb
new file mode 100644
index 00000000..2310a240
--- /dev/null
+++ b/app/helpers/users_helper.rb
@@ -0,0 +1,2 @@
+module UsersHelper
+end
diff --git a/app/inputs/date_picker_input.rb b/app/inputs/date_picker_input.rb
new file mode 100644
index 00000000..57ced21a
--- /dev/null
+++ b/app/inputs/date_picker_input.rb
@@ -0,0 +1,5 @@
+class DatePickerInput < SimpleForm::Inputs::StringInput
+ def input
+ @builder.text_field(attribute_name, input_html_options.merge({class: 'datepicker'}))
+ end
+end
\ No newline at end of file
diff --git a/app/mailers/mailer.rb b/app/mailers/mailer.rb
new file mode 100644
index 00000000..30eb44a7
--- /dev/null
+++ b/app/mailers/mailer.rb
@@ -0,0 +1,101 @@
+# encoding: utf-8
+# ActionMailer class that handles all emails for the FoodSoft.
+class Mailer < ActionMailer::Base
+
+ layout 'email' # Use views/layouts/email.txt.erb
+
+ default from: "FoodSoft <#{FoodsoftConfig[:email_sender]}>",
+ sender: FoodsoftConfig[:email_sender],
+ errors_to: FoodsoftConfig[:email_sender]
+
+ # Sends an email copy of the given internal foodsoft message.
+ def foodsoft_message(message, recipient)
+ set_foodcoop_scope
+ @message = message
+
+ mail subject: "[#{FoodsoftConfig[:name]}] " + message.subject,
+ to: recipient.email,
+ from: "#{message.sender.nick} <#{message.sender.email}>"
+ end
+
+ # Sends an email with instructions on how to reset the password.
+ # Assumes user.setResetPasswordToken has been successfully called already.
+ def reset_password(user)
+ set_foodcoop_scope
+ @user = user
+ @link = new_password_url(id: @user.id, token: @user.reset_password_token)
+
+ mail :to => @user.email,
+ :subject => "[#{FoodsoftConfig[:name]}] " + I18n.t('mailer.reset_password.subject', :username => @user.nick)
+ end
+
+ # Sends an invite email.
+ def invite(invite)
+ set_foodcoop_scope
+ @invite = invite
+ @link = accept_invitation_url(token: @invite.token)
+
+ mail :to => @invite.email,
+ :subject => I18n.t('mailer.invite.subject')
+ end
+
+ # Notify user of upcoming task.
+ def upcoming_tasks(user, task)
+ set_foodcoop_scope
+ @user = user
+ @task = task
+
+ mail :to => user.email,
+ :subject => "[#{FoodsoftConfig[:name]}] " + I18n.t('mailer.upcoming_tasks.subject')
+ end
+
+ # Sends order result for specific Ordergroup
+ def order_result(user, group_order)
+ set_foodcoop_scope
+ @order = group_order.order
+ @group_order = group_order
+
+ mail :to => user.email,
+ :subject => "[#{FoodsoftConfig[:name]}] " + I18n.t('mailer.order_result.subject', :name => group_order.order.name)
+ end
+
+ # Notify user if account balance is less than zero
+ def negative_balance(user,transaction)
+ set_foodcoop_scope
+ @group = user.ordergroup
+ @transaction = transaction
+
+ mail :to => user.email,
+ :subject => "[#{FoodsoftConfig[:name]}] " + I18n.t('mailer.negative_balance')
+ end
+
+ def feedback(user, feedback)
+ set_foodcoop_scope
+ @user = user
+ @feedback = feedback
+
+ mail :to => FoodsoftConfig[:notification]["error_recipients"],
+ :from => "#{user.nick} <#{user.email}>",
+ :sender => FoodsoftConfig[:notification]["sender_address"],
+ :errors_to => FoodsoftConfig[:notification]["sender_address"],
+ :subject => "[#{FoodsoftConfig[:name]}] " + I18n.t('mailer.feedback.subject', :email => user.email)
+ end
+
+ def not_enough_users_assigned(task, user)
+ set_foodcoop_scope
+ @task = task
+ @user = user
+
+ mail :to => user.email,
+ :subject => "[#{FoodsoftConfig[:name]}] " + I18n.t('mailer.not_enough_users_assigned.subject', :task => task.name)
+ end
+
+ private
+
+ def set_foodcoop_scope(foodcoop = FoodsoftConfig.scope)
+ ActionMailer::Base.default_url_options[:protocol] = FoodsoftConfig[:protocol]
+ ActionMailer::Base.default_url_options[:host] = FoodsoftConfig[:host]
+ ActionMailer::Base.default_url_options[:foodcoop] = foodcoop
+ end
+
+end
diff --git a/app/models/article.rb b/app/models/article.rb
index dcec5a09..3755a4b2 100644
--- a/app/models/article.rb
+++ b/app/models/article.rb
@@ -1,67 +1,31 @@
-# == Schema Information
-#
-# Table name: articles
-#
-# id :integer not null, primary key
-# name :string(255) default(""), not null
-# supplier_id :integer default(0), not null
-# article_category_id :integer default(0), not null
-# unit :string(255) default(""), not null
-# note :string(255)
-# availability :boolean default(TRUE), not null
-# manufacturer :string(255)
-# origin :string(255)
-# shared_updated_on :datetime
-# price :decimal(, )
-# tax :float
-# deposit :decimal(, ) default(0.0)
-# unit_quantity :integer default(1), not null
-# order_number :string(255)
-# created_at :datetime
-# updated_at :datetime
-# quantity :integer default(0)
-# deleted_at :datetime
-# type :string(255)
-#
-
+# encoding: utf-8
class Article < ActiveRecord::Base
- acts_as_paranoid # Avoid deleting the article for consistency of order-results
extend ActiveSupport::Memoizable # Ability to cache method results. Use memoize :expensive_method
+ # Replace numeric seperator with database format
+ localize_input_of :price, :tax, :deposit
+
# Associations
belongs_to :supplier
belongs_to :article_category
has_many :article_prices, :order => "created_at DESC"
- named_scope :available, :conditions => {:availability => true}
- named_scope :not_in_stock, :conditions => {:type => nil}
+ scope :undeleted, -> { where(deleted_at: nil) }
+ scope :available, -> { undeleted.where(availability: true) }
+ scope :not_in_stock, :conditions => {:type => nil}
# Validations
- validates_presence_of :name, :unit, :price, :tax, :deposit, :unit_quantity, :supplier_id, :article_category_id
+ validates_presence_of :name, :unit, :price, :tax, :deposit, :unit_quantity, :supplier_id, :article_category
validates_length_of :name, :in => 4..60
validates_length_of :unit, :in => 2..15
- validates_numericality_of :price, :unit_quantity, :greater_than => 0
+ validates_numericality_of :price, :greater_than_or_equal_to => 0
+ validates_numericality_of :unit_quantity, :greater_than => 0
validates_numericality_of :deposit, :tax
validates_uniqueness_of :name, :scope => [:supplier_id, :deleted_at, :type]
# Callbacks
before_save :update_price_history
before_destroy :check_article_in_use
-
- # Custom attribute setter that accepts decimal numbers using localized decimal separator.
- def price=(price)
- self[:price] = String.delocalized_decimal(price)
- end
-
- # Custom attribute setter that accepts decimal numbers using localized decimal separator.
- def tax=(tax)
- self[:tax] = String.delocalized_decimal(tax)
- end
-
- # Custom attribute setter that accepts decimal numbers using localized decimal separator.
- def deposit=(deposit)
- self[:deposit] = String.delocalized_decimal(deposit)
- end
# The financial gross, net plus tax and deposti
def gross_price
@@ -70,7 +34,7 @@ class Article < ActiveRecord::Base
# The price for the foodcoop-member.
def fc_price
- (gross_price * (Foodsoft.config[:price_markup] / 100 + 1)).round(2)
+ (gross_price * (FoodsoftConfig[:price_markup] / 100 + 1)).round(2)
end
# Returns true if article has been updated at least 2 days ago
@@ -86,6 +50,11 @@ class Article < ActiveRecord::Base
end
memoize :in_open_order
+ # Returns true if the article has been ordered in the given order at least once
+ def ordered_in_order?(order)
+ order.order_articles.where(article_id: id).where('quantity > 0').one?
+ end
+
# this method checks, if the shared_article has been changed
# unequal attributes will returned in array
# if only the timestamps differ and the attributes are equal,
@@ -157,8 +126,8 @@ class Article < ActiveRecord::Base
false
end
else # get factors for fc and supplier
- fc_unit_factor = Foodsoft.config[:units][self.unit]
- supplier_unit_factor = Foodsoft.config[:units][self.shared_article.unit]
+ fc_unit_factor = FoodsoftConfig[:units][self.unit]
+ supplier_unit_factor = FoodsoftConfig[:units][self.shared_article.unit]
if fc_unit_factor and supplier_unit_factor
convertion_factor = fc_unit_factor / supplier_unit_factor
new_price = BigDecimal((convertion_factor * shared_article.price).to_s).round(2)
@@ -173,11 +142,20 @@ class Article < ActiveRecord::Base
end
end
+ def deleted?
+ deleted_at.present?
+ end
+
+ def mark_as_deleted
+ check_article_in_use
+ update_column :deleted_at, Time.now
+ end
+
protected
# Checks if the article is in use before it will deleted
def check_article_in_use
- raise self.name.to_s + " kann nicht gelöscht werden. Der Artikel befindet sich in einer laufenden Bestellung!" if self.in_open_order
+ raise I18n.t('articles.model.error_in_use', :article => self.name.to_s) if self.in_open_order
end
# Create an ArticlePrice, when the price-attr are changed.
diff --git a/app/models/article_category.rb b/app/models/article_category.rb
index 2fc39aaf..c93e1c31 100644
--- a/app/models/article_category.rb
+++ b/app/models/article_category.rb
@@ -1,17 +1,15 @@
class ArticleCategory < ActiveRecord::Base
has_many :articles
-
- validates_length_of :name, :in => 2..20
- validates_uniqueness_of :name
+
+ validates :name, :presence => true, :uniqueness => true, :length => { :in => 2..20 }
+
+ before_destroy :check_for_associated_articles
+
+ protected
+
+ def check_for_associated_articles
+ raise I18n.t('activerecord.errors.has_many_left', collection: Article.model_name.human) if articles.undeleted.exists?
+ end
end
-# == Schema Information
-#
-# Table name: article_categories
-#
-# id :integer(4) not null, primary key
-# name :string(255) default(""), not null
-# description :string(255)
-#
-
diff --git a/app/models/article_price.rb b/app/models/article_price.rb
index 32f7faeb..29e8d507 100644
--- a/app/models/article_price.rb
+++ b/app/models/article_price.rb
@@ -4,22 +4,11 @@ class ArticlePrice < ActiveRecord::Base
has_many :order_articles
validates_presence_of :price, :tax, :deposit, :unit_quantity
- validates_numericality_of :price, :unit_quantity, :greater_than => 0
-
- # Custom attribute setter that accepts decimal numbers using localized decimal separator.
- def price=(price)
- self[:price] = String.delocalized_decimal(price)
- end
+ validates_numericality_of :price, :greater_than_or_equal_to => 0
+ validates_numericality_of :unit_quantity, :greater_than => 0
+ validates_numericality_of :deposit, :tax
- # Custom attribute setter that accepts decimal numbers using localized decimal separator.
- def tax=(tax)
- self[:tax] = String.delocalized_decimal(tax)
- end
-
- # Custom attribute setter that accepts decimal numbers using localized decimal separator.
- def deposit=(deposit)
- self[:deposit] = String.delocalized_decimal(deposit)
- end
+ localize_input_of :price, :tax, :deposit
# The financial gross, net plus tax and deposit.
def gross_price
@@ -28,20 +17,7 @@ class ArticlePrice < ActiveRecord::Base
# The price for the foodcoop-member.
def fc_price
- (gross_price * (Foodsoft.config[:price_markup] / 100 + 1)).round(2)
+ (gross_price * (FoodsoftConfig[:price_markup] / 100 + 1)).round(2)
end
end
-# == Schema Information
-#
-# Table name: article_prices
-#
-# id :integer(4) not null, primary key
-# article_id :integer(4)
-# price :decimal(8, 2) default(0.0), not null
-# tax :decimal(8, 2) default(0.0), not null
-# deposit :decimal(8, 2) default(0.0), not null
-# unit_quantity :integer(4)
-# created_at :datetime
-#
-
diff --git a/app/models/assignment.rb b/app/models/assignment.rb
index 6408b9e8..9781b7b0 100644
--- a/app/models/assignment.rb
+++ b/app/models/assignment.rb
@@ -2,26 +2,6 @@ class Assignment < ActiveRecord::Base
belongs_to :user
belongs_to :task
-
- # after user is assigned mark task as assigned
- def after_create
- self.task.update_attribute(:assigned, true)
- end
-
- # update assigned-attribute
- def after_destroy
- self.task.update_attribute(:assigned, false) if self.task.assignments.empty?
- end
end
-# == Schema Information
-#
-# Table name: assignments
-#
-# id :integer(4) not null, primary key
-# user_id :integer(4) default(0), not null
-# task_id :integer(4) default(0), not null
-# accepted :boolean(1) default(FALSE)
-#
-
diff --git a/app/models/delivery.rb b/app/models/delivery.rb
index da0a0d8d..3add6fdf 100644
--- a/app/models/delivery.rb
+++ b/app/models/delivery.rb
@@ -4,7 +4,7 @@ class Delivery < ActiveRecord::Base
has_one :invoice
has_many :stock_changes, :dependent => :destroy
- named_scope :recent, :order => 'created_at DESC', :limit => 10
+ scope :recent, :order => 'created_at DESC', :limit => 10
validates_presence_of :supplier_id
@@ -19,14 +19,3 @@ class Delivery < ActiveRecord::Base
end
-# == Schema Information
-#
-# Table name: deliveries
-#
-# id :integer(4) not null, primary key
-# supplier_id :integer(4)
-# delivered_on :date
-# created_at :datetime
-# note :text
-#
-
diff --git a/app/models/financial_transaction.rb b/app/models/financial_transaction.rb
index c1b8165d..354a3d2a 100644
--- a/app/models/financial_transaction.rb
+++ b/app/models/financial_transaction.rb
@@ -4,25 +4,14 @@ class FinancialTransaction < ActiveRecord::Base
belongs_to :ordergroup
belongs_to :user
- validates_presence_of :note, :user_id, :ordergroup_id
+ validates_presence_of :amount, :note, :user_id, :ordergroup_id
validates_numericality_of :amount
- # Custom attribute setter that accepts decimal numbers using localized decimal separator.
- def amount=(amount)
- self[:amount] = String.delocalized_decimal(amount)
- end
+ localize_input_of :amount
+ # Use this save method instead of simple save and after callback
+ def add_transaction!
+ ordergroup.add_financial_transaction! amount, note, user
+ end
end
-# == Schema Information
-#
-# Table name: financial_transactions
-#
-# id :integer(4) not null, primary key
-# ordergroup_id :integer(4) default(0), not null
-# amount :decimal(8, 2) default(0.0), not null
-# note :text default(""), not null
-# user_id :integer(4) default(0), not null
-# created_on :datetime not null
-#
-
diff --git a/app/models/group.rb b/app/models/group.rb
index 36953268..092c0119 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -1,12 +1,15 @@
# Groups organize the User.
# A Member gets the roles from the Group
class Group < ActiveRecord::Base
- has_many :memberships, :dependent => :destroy
+ has_many :memberships
has_many :users, :through => :memberships
+
+ validates :name, :presence => true, :length => {:in => 1..25}
- validates_length_of :name, :in => 1..25
- validates_uniqueness_of :name
-
+ attr_reader :user_tokens
+
+ scope :undeleted, -> { where(deleted_at: nil) }
+
# Returns true if the given user if is an member of this group.
def member?(user)
memberships.find_by_user_id(user.id)
@@ -16,58 +19,23 @@ class Group < ActiveRecord::Base
def non_members
User.all(:order => 'nick').reject { |u| users.include?(u) }
end
-
- # Check before destroy a group, if this is the last group with admin role
- def before_destroy
- if self.role_admin == true && Group.find_all_by_role_admin(true).size == 1
- raise "Die letzte Gruppe mit Admin-Rechten darf nicht gelöscht werden"
- end
- end
-
- protected
-
- # validates uniqueness of the Group.name. Checks groups and ordergroups
- def validate
- errors.add(:name, "ist schon vergeben") if (group = Group.find_by_name(name) || group = Ordergroup.find_by_name(name)) && self != group
+
+ def user_tokens=(ids)
+ self.user_ids = ids.split(",")
end
- # add validation check on update
- def validate_on_update
- # error if this is the last group with admin role and role_admin should set to false
- if self.role_admin == false && Group.find_all_by_role_admin(true).size == 1 && self == Group.find(:first, :conditions => "role_admin = 1")
- errors.add(:role_admin, "Der letzten Gruppe mit Admin-Rechten darf die Admin-Rolle nicht entzogen werden")
+ def deleted?
+ deleted_at.present?
+ end
+
+ def mark_as_deleted
+ # TODO: Checks for participating in not closed orders
+ transaction do
+ memberships.destroy_all
+ # TODO: What should happen to users?
+ update_column :deleted_at, Time.now
end
end
-
end
-# == Schema Information
-#
-# Table name: groups
-#
-# id :integer(4) not null, primary key
-# type :string(255) default(""), not null
-# name :string(255) default(""), not null
-# description :string(255)
-# account_balance :decimal(8, 2) default(0.0), not null
-# account_updated :datetime
-# created_on :datetime not null
-# role_admin :boolean(1) default(FALSE), not null
-# role_suppliers :boolean(1) default(FALSE), not null
-# role_article_meta :boolean(1) default(FALSE), not null
-# role_finance :boolean(1) default(FALSE), not null
-# role_orders :boolean(1) default(FALSE), not null
-# weekly_task :boolean(1) default(FALSE)
-# weekday :integer(4)
-# task_name :string(255)
-# task_description :string(255)
-# task_required_users :integer(4) default(1)
-# deleted_at :datetime
-# contact_person :string(255)
-# contact_phone :string(255)
-# contact_address :string(255)
-# stats :text
-# task_duration :integer(4) default(1)
-#
-
diff --git a/app/models/group_order.rb b/app/models/group_order.rb
index 9a0a7ad6..35bec437 100644
--- a/app/models/group_order.rb
+++ b/app/models/group_order.rb
@@ -1,6 +1,8 @@
# A GroupOrder represents an Order placed by an Ordergroup.
class GroupOrder < ActiveRecord::Base
-
+
+ attr_accessor :group_order_articles_attributes
+
belongs_to :order
belongs_to :ordergroup
has_many :group_order_articles, :dependent => :destroy
@@ -12,41 +14,74 @@ class GroupOrder < ActiveRecord::Base
validates_numericality_of :price
validates_uniqueness_of :ordergroup_id, :scope => :order_id # order groups can only order once per order
- named_scope :open, lambda { {:conditions => ["order_id IN (?)", Order.open.collect(&:id)]} }
- named_scope :finished, lambda { {:conditions => ["order_id IN (?)", Order.finished_not_closed.collect(&:id)]} }
-
- # Updates the "price" attribute.
- # Until the order is finished this will be the maximum price or
- # the minimum price depending on configuration. When the order is finished it
- # will be the value depending of the article results.
- def update_price!
- total = 0
- for article in group_order_articles.find(:all, :include => :order_article)
- unless order.finished?
- if Foodsoft.config[:tolerance_is_costly]
- total += article.order_article.article.fc_price * (article.quantity + article.tolerance)
- else
- total += article.order_article.article.fc_price * article.quantity
- end
- else
- total += article.order_article.price.fc_price * article.result
+ scope :in_open_orders, joins(:order).merge(Order.open)
+ scope :in_finished_orders, joins(:order).merge(Order.finished_not_closed)
+
+ # Generate some data for the javascript methods in ordering view
+ def load_data
+ data = {}
+ data[:available_funds] = ordergroup.get_available_funds(self)
+
+ # load prices and other stuff....
+ data[:order_articles] = {}
+ order.articles_grouped_by_category.each do |article_category, order_articles|
+ order_articles.each do |order_article|
+
+ # Get the result of last time ordering, if possible
+ goa = group_order_articles.detect { |goa| goa.order_article_id == order_article.id }
+
+ # Build hash with relevant data
+ data[:order_articles][order_article.id] = {
+ :price => order_article.article.fc_price,
+ :unit => order_article.article.unit_quantity,
+ :quantity => (goa ? goa.quantity : 0),
+ :others_quantity => order_article.quantity - (goa ? goa.quantity : 0),
+ :used_quantity => (goa ? goa.result(:quantity) : 0),
+ :tolerance => (goa ? goa.result(:tolerance) : 0),
+ :others_tolerance => order_article.tolerance - (goa ? goa.result(:tolerance) : 0),
+ :used_tolerance => (goa ? goa.result(:tolerance) : 0),
+ :total_price => (goa ? goa.total_price : 0),
+ :missing_units => order_article.missing_units,
+ :quantity_available => (order.stockit? ? order_article.article.quantity_available : 0)
+ }
end
end
+
+ data
+ end
+
+ def save_group_order_articles
+ for order_article in order.order_articles
+ # Find the group_order_article, create a new one if necessary...
+ group_order_article = group_order_articles.find_or_create_by_order_article_id(order_article.id)
+
+ # Get ordered quantities and update group_order_articles/_quantities...
+ quantities = group_order_articles_attributes.fetch(order_article.id.to_s, {:quantity => 0, :tolerance => 0})
+ group_order_article.update_quantities(quantities[:quantity].to_i, quantities[:tolerance].to_i)
+
+ # Also update results for the order_article
+ logger.debug "[save_group_order_articles] update order_article.results!"
+ order_article.update_results!
+ end
+
+ # set attributes to nil to avoid and infinite loop of
+ end
+
+ # Updates the "price" attribute.
+ def update_price!
+ total = group_order_articles.includes(:order_article => [:article, :article_price]).to_a.sum(&:total_price)
update_attribute(:price, total)
end
+
+ # Save GroupOrder and updates group_order_articles/quantities accordingly
+ def save_ordering!
+ transaction do
+ save!
+ save_group_order_articles
+ update_price!
+ end
+ end
+
end
-# == Schema Information
-#
-# Table name: group_orders
-#
-# id :integer(4) not null, primary key
-# ordergroup_id :integer(4) default(0), not null
-# order_id :integer(4) default(0), not null
-# price :decimal(8, 2) default(0.0), not null
-# lock_version :integer(4) default(0), not null
-# updated_on :datetime not null
-# updated_by_user_id :integer(4)
-#
-
diff --git a/app/models/group_order_article.rb b/app/models/group_order_article.rb
index 9612917e..11f3b447 100644
--- a/app/models/group_order_article.rb
+++ b/app/models/group_order_article.rb
@@ -8,21 +8,26 @@ class GroupOrderArticle < ActiveRecord::Base
belongs_to :order_article
has_many :group_order_article_quantities, :dependent => :destroy
- validates_presence_of :group_order_id, :order_article_id
+ validates_presence_of :group_order, :order_article
validates_inclusion_of :quantity, :in => 0..99
validates_inclusion_of :result, :in => 0..99, :allow_nil => true
validates_inclusion_of :tolerance, :in => 0..99
validates_uniqueness_of :order_article_id, :scope => :group_order_id # just once an article per group order
- attr_accessor :ordergroup_id # To create an new GroupOrder if neccessary
+ scope :ordered, :conditions => 'result > 0'
- named_scope :ordered, :conditions => 'result > 0'
+ localize_input_of :result
- # Custom attribute setter that accepts decimal numbers using localized decimal separator.
- def result=(result)
- self[:result] = String.delocalized_decimal(result)
+ # Setter used in group_order_article#new
+ # We have to create an group_order, if the ordergroup wasn't involved in the order yet
+ def ordergroup_id=(id)
+ self.group_order = GroupOrder.find_or_initialize_by_order_id_and_ordergroup_id(order_article.order_id, id)
end
-
+
+ def ordergroup_id
+ group_order.try(:ordergroup_id)
+ end
+
# Updates the quantity/tolerance for this GroupOrderArticle by updating both GroupOrderArticle properties
# and the associated GroupOrderArticleQuantities chronologically.
#
@@ -30,17 +35,17 @@ class GroupOrderArticle < ActiveRecord::Base
def update_quantities(quantity, tolerance)
logger.debug("GroupOrderArticle[#{id}].update_quantities(#{quantity}, #{tolerance})")
logger.debug("Current quantity = #{self.quantity}, tolerance = #{self.tolerance}")
-
+
# Get quantities ordered with the newest item first.
quantities = group_order_article_quantities.find(:all, :order => 'created_on desc')
logger.debug("GroupOrderArticleQuantity items found: #{quantities.size}")
- if (quantities.size == 0)
+ if (quantities.size == 0)
# There is no GroupOrderArticleQuantity item yet, just insert with desired quantities...
logger.debug("No quantities entry at all, inserting a new one with the desired quantities")
quantities.push(GroupOrderArticleQuantity.new(:group_order_article => self, :quantity => quantity, :tolerance => tolerance))
- self.quantity, self.tolerance = quantity, tolerance
- else
+ self.quantity, self.tolerance = quantity, tolerance
+ else
# Decrease quantity/tolerance if necessary by going through the existing items and decreasing their values...
i = 0
while (i < quantities.size && (quantity < self.quantity || tolerance < self.tolerance))
@@ -50,31 +55,31 @@ class GroupOrderArticle < ActiveRecord::Base
delta = (delta > quantities[i].quantity ? quantities[i].quantity : delta)
logger.debug("Decreasing quantity by #{delta}")
quantities[i].quantity -= delta
- self.quantity -= delta
+ self.quantity -= delta
end
if (tolerance < self.tolerance && quantities[i].tolerance > 0)
delta = self.tolerance - tolerance
delta = (delta > quantities[i].tolerance ? quantities[i].tolerance : delta)
logger.debug("Decreasing tolerance by #{delta}")
quantities[i].tolerance -= delta
- self.tolerance -= delta
+ self.tolerance -= delta
end
i += 1
- end
+ end
# If there is at least one increased value: insert a new GroupOrderArticleQuantity object
if (quantity > self.quantity || tolerance > self.tolerance)
logger.debug("Inserting a new GroupOrderArticleQuantity")
quantities.insert(0, GroupOrderArticleQuantity.new(
- :group_order_article => self,
- :quantity => (quantity > self.quantity ? quantity - self.quantity : 0),
- :tolerance => (tolerance > self.tolerance ? tolerance - self.tolerance : 0)
+ :group_order_article => self,
+ :quantity => (quantity > self.quantity ? quantity - self.quantity : 0),
+ :tolerance => (tolerance > self.tolerance ? tolerance - self.tolerance : 0)
))
# Recalc totals:
self.quantity += quantities[0].quantity
- self.tolerance += quantities[0].tolerance
+ self.tolerance += quantities[0].tolerance
end
end
-
+
# Check if something went terribly wrong and quantites have not been adjusted as desired.
if (self.quantity != quantity || self.tolerance != tolerance)
raise 'Invalid state: unable to update GroupOrderArticle/-Quantities to desired quantities!'
@@ -82,7 +87,7 @@ class GroupOrderArticle < ActiveRecord::Base
# Remove zero-only items.
quantities = quantities.reject { | q | q.quantity == 0 && q.tolerance == 0}
-
+
# Save
transaction do
quantities.each { | i | i.save! }
@@ -90,7 +95,7 @@ class GroupOrderArticle < ActiveRecord::Base
save!
end
end
-
+
# Determines how many items of this article the Ordergroup receives.
# Returns a hash with three keys: :quantity / :tolerance / :total
#
@@ -102,15 +107,15 @@ class GroupOrderArticle < ActiveRecord::Base
# Get total
total = stockit ? order_article.article.quantity : order_article.units_to_order * order_article.price.unit_quantity
logger.debug("<#{order_article.article.name}>.unitsToOrder => items ordered: #{order_article.units_to_order} => #{total}")
-
+
if (total > 0)
# In total there are enough units ordered. Now check the individual result for the ordergroup (group_order).
#
# Get all GroupOrderArticleQuantities for this OrderArticle...
order_quantities = GroupOrderArticleQuantity.all(
- :conditions => ["group_order_article_id IN (?)", order_article.group_order_article_ids], :order => 'created_on')
+ :conditions => ["group_order_article_id IN (?)", order_article.group_order_article_ids], :order => 'created_on')
logger.debug("GroupOrderArticleQuantity records found: #{order_quantities.size}")
-
+
# Determine quantities to be ordered...
total_quantity = i = 0
while (i < order_quantities.size && total_quantity < total)
@@ -137,10 +142,10 @@ class GroupOrderArticle < ActiveRecord::Base
i += 1
end
end
-
+
logger.debug("determined quantity/tolerance/total: #{quantity} / #{tolerance} / #{quantity + tolerance}")
end
-
+
{:quantity => quantity, :tolerance => tolerance, :total => quantity + tolerance}
end
memoize :calculate_result
@@ -156,20 +161,23 @@ class GroupOrderArticle < ActiveRecord::Base
def save_results!
self.update_attribute(:result, calculate_result[:total])
end
-
+
+ # Returns total price for this individual article
+ # Until the order is finished this will be the maximum price or
+ # the minimum price depending on configuration. When the order is finished it
+ # will be the value depending of the article results.
+ def total_price(order_article = self.order_article)
+ unless order_article.order.finished?
+ if FoodsoftConfig[:tolerance_is_costly]
+ order_article.article.fc_price * (quantity + tolerance)
+ else
+ order_article.article.fc_price * quantity
+ end
+ else
+ order_article.price.fc_price * result
+ end
+ end
+
end
-# == Schema Information
-#
-# Table name: group_order_articles
-#
-# id :integer(4) not null, primary key
-# group_order_id :integer(4) default(0), not null
-# order_article_id :integer(4) default(0), not null
-# quantity :integer(4) default(0), not null
-# tolerance :integer(4) default(0), not null
-# updated_on :datetime not null
-# result :decimal(8, 3)
-#
-
diff --git a/app/models/group_order_article_quantity.rb b/app/models/group_order_article_quantity.rb
index 5d31fefe..95234f7e 100644
--- a/app/models/group_order_article_quantity.rb
+++ b/app/models/group_order_article_quantity.rb
@@ -11,14 +11,3 @@ class GroupOrderArticleQuantity < ActiveRecord::Base
end
-# == Schema Information
-#
-# Table name: group_order_article_quantities
-#
-# id :integer(4) not null, primary key
-# group_order_article_id :integer(4) default(0), not null
-# quantity :integer(4) default(0)
-# tolerance :integer(4) default(0)
-# created_on :datetime not null
-#
-
diff --git a/app/models/invite.rb b/app/models/invite.rb
index d8eed384..21cb1b9d 100644
--- a/app/models/invite.rb
+++ b/app/models/invite.rb
@@ -10,40 +10,26 @@ class Invite < ActiveRecord::Base
validates_presence_of :group
validates_presence_of :token
validates_presence_of :expires_at
+ validate :email_not_already_registered, :on => :create
+
+ before_validation :set_token_and_expires_at
protected
# Before validation, set token and expires_at.
- def before_validation
+ def set_token_and_expires_at
self.token = Digest::SHA1.hexdigest(Time.now.to_s + rand(100).to_s)
self.expires_at = Time.now.advance(:days => 7)
end
- # Sends an email to the invited user.
- def after_create
- Mailer.deliver_invite(self)
- end
-
private
# Custom validation: check that email does not already belong to a registered user.
- def validate_on_create
+ def email_not_already_registered
unless User.find_by_email(self.email).nil?
- errors.add(:email, 'ist bereits in Verwendung. Person ist schon Mitglied der Foodcoop.')
+ errors.add(:email, I18n.t('invites.errors.already_member'))
end
end
end
-# == Schema Information
-#
-# Table name: invites
-#
-# id :integer(4) not null, primary key
-# token :string(255) default(""), not null
-# expires_at :datetime not null
-# group_id :integer(4) default(0), not null
-# user_id :integer(4) default(0), not null
-# email :string(255) default(""), not null
-#
-
diff --git a/app/models/invoice.rb b/app/models/invoice.rb
index b65305e5..0feb3ede 100644
--- a/app/models/invoice.rb
+++ b/app/models/invoice.rb
@@ -5,23 +5,12 @@ class Invoice < ActiveRecord::Base
belongs_to :order
validates_presence_of :supplier_id
+ validates_numericality_of :amount, :deposit, :deposit_credit
- named_scope :unpaid, :conditions => { :paid_on => nil }
+ scope :unpaid, :conditions => { :paid_on => nil }
- # Custom attribute setter that accepts decimal numbers using localized decimal separator.
- def amount=(amount)
- self[:amount] = String.delocalized_decimal(amount)
- end
-
- # Custom attribute setter that accepts decimal numbers using localized decimal separator.
- def deposit=(deposit)
- self[:deposit] = String.delocalized_decimal(deposit)
- end
-
- # Custom attribute setter that accepts decimal numbers using localized decimal separator.
- def deposit_credit=(deposit)
- self[:deposit_credit] = String.delocalized_decimal(deposit)
- end
+ # Replace numeric seperator with database format
+ localize_input_of :amount, :deposit, :deposit_credit
# Amount without deposit
def net_amount
@@ -30,22 +19,3 @@ class Invoice < ActiveRecord::Base
end
-# == Schema Information
-#
-# Table name: invoices
-#
-# id :integer(4) not null, primary key
-# supplier_id :integer(4)
-# delivery_id :integer(4)
-# order_id :integer(4)
-# number :string(255)
-# date :date
-# paid_on :date
-# note :text
-# amount :decimal(8, 2) default(0.0), not null
-# deposit :decimal(8, 2) default(0.0), not null
-# deposit_credit :decimal(8, 2) default(0.0), not null
-# created_at :datetime
-# updated_at :datetime
-#
-
diff --git a/app/models/mailer.rb b/app/models/mailer.rb
deleted file mode 100644
index 761ac2e9..00000000
--- a/app/models/mailer.rb
+++ /dev/null
@@ -1,84 +0,0 @@
-# ActionMailer class that handles all emails for the FoodSoft.
-class Mailer < ActionMailer::Base
-
- layout 'email' # Use views/layouts/email.html.erb
-
- # Sends an email copy of the given internal foodsoft message.
- def message(message, recipient)
- headers 'Sender' => Foodsoft.config[:email_sender], 'Errors-To' => Foodsoft.config[:email_sender]
- subject "[#{Foodsoft.config[:name]}] " + message.subject
- recipients recipient.email
- from "#{message.sender.nick} <#{message.sender.email}>"
- body :body => message.body,
- :sender => message.sender.nick,
- :recipients => recipient.nick,
- :reply => url_for(:controller => "messages", :action => "reply", :id => message.id),
- :link => url_for(:controller => "messages", :action => "show", :id => message.id),
- :profile => url_for(:controller => "home", :action => "profile")
- end
-
- # Sends an email with instructions on how to reset the password.
- # Assumes user.setResetPasswordToken has been successfully called already.
- def reset_password(user)
- prepare_system_message(user)
- subject "[#{Foodsoft.config[:name]}] Neues Passwort für/ New password for #{user.nick}"
- body :user => user,
- :link => url_for(:controller => "login", :action => "password", :id => user.id, :token => user.reset_password_token)
- end
-
- # Sends an invite email.
- def invite(invite)
- prepare_system_message(invite)
- subject "Einladung in die Foodcoop #{Foodsoft.config[:name]} - Invitation to the Foodcoop"
- body :invite => invite,
- :link => url_for(:controller => "login", :action => "invite", :id => invite.token)
- end
-
- # Notify user of upcoming task.
- def upcoming_tasks(user, task)
- prepare_system_message(user)
- subject "[#{Foodsoft.config[:name]}] Aufgaben werden fällig!"
- body :user => user,
- :task => task
- end
-
- # Sends order result for specific Ordergroup
- def order_result(user, group_order)
- prepare_system_message(user)
- subject "[#{Foodsoft.config[:name]}] Bestellung beendet: #{group_order.order.name}"
- body :order => group_order.order,
- :group_order => group_order
- end
-
- # Notify user if account balance is less than zero
- def negative_balance(user,transaction)
- prepare_system_message(user)
- subject "[#{Foodsoft.config[:name]}] Gruppenkonto im Minus"
- body :group => user.ordergroup,
- :transaction => transaction
- end
-
- def feedback(user, message)
- subject "[Foodsoft] Feeback von #{user.email}"
- recipients Foodsoft.config[:notification]["error_recipients"]
- from "#{user.nick} <#{user.email}>"
- headers 'Sender' => Foodsoft.config[:notification]["sender_address"],
- 'Errors-To' => Foodsoft.config[:notification]["sender_address"]
- body :user => user, :message => message
- end
-
- def not_enough_users_assigned(task,user)
- prepare_system_message(user)
- subject "[#{Foodsoft.config[:name]}] #{task.name} braucht noch Leute!"
- body :task => task, :user => user,
- :task_url => url_for(:controller => "tasks", :action => "workgroup", :id => task.workgroup_id)
- end
-
- protected
-
- def prepare_system_message(recipient)
- recipients recipient.email
- from "FoodSoft <#{Foodsoft.config[:email_sender]}>"
- end
-
-end
diff --git a/app/models/membership.rb b/app/models/membership.rb
index d448ffe3..5af05c41 100644
--- a/app/models/membership.rb
+++ b/app/models/membership.rb
@@ -2,22 +2,17 @@ class Membership < ActiveRecord::Base
belongs_to :user
belongs_to :group
+
+ before_destroy :check_last_admin
# messages
- ERR_NO_ADMIN_MEMBER_DELETE = "Mitgliedschaft kann nicht beendet werden. Du bist die letzte Administratorin"
-
+ ERR_NO_ADMIN_MEMBER_DELETE = I18n.t('model.membership.no_admin_delete')
+
+ protected
+
# check if this is the last admin-membership and deny
- def before_destroy
+ def check_last_admin
raise ERR_NO_ADMIN_MEMBER_DELETE if self.group.role_admin? && self.group.memberships.size == 1 && Group.find_all_by_role_admin(true).size == 1
end
end
-# == Schema Information
-#
-# Table name: memberships
-#
-# id :integer(4) not null, primary key
-# group_id :integer(4) default(0), not null
-# user_id :integer(4) default(0), not null
-#
-
diff --git a/app/models/message.rb b/app/models/message.rb
index 5311afbc..e14ad59e 100644
--- a/app/models/message.rb
+++ b/app/models/message.rb
@@ -2,11 +2,11 @@ class Message < ActiveRecord::Base
belongs_to :sender, :class_name => "User", :foreign_key => "sender_id"
serialize :recipients_ids, Array
- attr_accessor :sent_to_all, :group_id, :recipients_nicks
+ attr_accessor :sent_to_all, :group_id, :recipient_tokens, :reply_to
- named_scope :pending, :conditions => { :email_state => 0 }
- named_scope :sent, :conditions => { :email_state => 1 }
- named_scope :public, :conditions => {:private => false}
+ scope :pending, where(:email_state => 0)
+ scope :sent, where(:email_state => 1)
+ scope :public, where(:private => false)
# Values for the email_state attribute: :none, :pending, :sent, :failed
EMAIL_STATE = {
@@ -19,9 +19,13 @@ class Message < ActiveRecord::Base
validates_length_of :subject, :in => 1..255
validates_inclusion_of :email_state, :in => EMAIL_STATE.values
+ before_validation :clean_up_recipient_ids, :on => :create
- # clean up the recipients_ids
- def before_validation_on_create
+ def self.deliver(message_id)
+ find(message_id).deliver
+ end
+
+ def clean_up_recipient_ids
self.recipients_ids = recipients_ids.uniq.reject { |id| id.blank? } unless recipients_ids.nil?
self.recipients_ids = User.all.collect(&:id) if sent_to_all == "1"
end
@@ -36,64 +40,53 @@ class Message < ActiveRecord::Base
add_recipients Group.find(group_id).users unless group_id.blank?
end
- def recipients_nicks=(nicks)
- @recipients_nicks = nicks
- add_recipients nicks.split(",").collect { |nick| User.find_by_nick(nick) }
+ def recipient_tokens=(ids)
+ @recipient_tokens = ids
+ add_recipients ids.split(",").collect { |id| User.find(id) }
end
- def recipient=(user)
- @recipients_nicks = user.nick
+ def reply_to=(message_id)
+ @reply_to = Message.find(message_id)
+ add_recipients([@reply_to.sender])
+ self.subject = I18n.t('messages.model.reply_subject', :subject => @reply_to.subject)
+ self.body = I18n.t('messages.model.reply_header', :user => @reply_to.sender.nick, :when => I18n.l(@reply_to.created_at, :format => :short)) + "\n"
+ @reply_to.body.each_line{ |l| self.body += I18n.t('messages.model.reply_indent', :line => l) }
end
-
+
+ def mail_to=(user_id)
+ user = User.find(user_id)
+ add_recipients([user])
+ end
+
# Returns true if this message is a system message, i.e. was sent automatically by the FoodSoft itself.
def system_message?
self.sender_id.nil?
end
def sender_name
- system_message? ? 'Foodsoft' : sender.nick rescue "??"
+ system_message? ? I18n.t('layouts.foodsoft') : sender.nick rescue "??"
end
def recipients
User.find(recipients_ids)
- rescue ActiveRecord::RecordNotFound => error
- logger.warn "#{Foodsoft.env}: #{error.message}"
- User.find(recipients_ids.select { |id| User.exists?(id) }.uniq)
end
- # Sends all pending messages that are to be send as emails.
- def self.send_emails
- messages = Message.pending
- # Set all messages not pending, to avoid sending mails twice with different background processes
- messages.each { |m| m.update_attribute(:email_state, 2) }
-
- for message in messages
- for recipient in message.recipients
- if recipient.settings['messages.sendAsEmail'] == "1" && !recipient.email.blank?
- begin
- Mailer.deliver_message(message, recipient)
- rescue
- logger.warn "Deliver failed for #{recipient.nick}: #{recipient.email}"
- end
+ def deliver
+ for user in recipients
+ if user.receive_email?
+ begin
+ Mailer.foodsoft_message(self, user).deliver
+ rescue
+ Rails.logger.warn "Deliver failed for #{user.nick}: #{user.email}"
end
end
- message.update_attribute(:email_state, 1) # Set email state to 'sent'
end
+ update_attribute(:email_state, 1)
+ end
+
+ def is_readable_for?(user)
+ !private || sender == user || recipients_ids.include?(user.id)
end
end
-# == Schema Information
-#
-# Table name: messages
-#
-# id :integer(4) not null, primary key
-# sender_id :integer(4)
-# recipients_ids :text
-# subject :string(255) not null
-# body :text
-# email_state :integer(4) default(0), not null
-# private :boolean(1) default(FALSE)
-# created_at :datetime
-#
-
diff --git a/app/models/order.rb b/app/models/order.rb
index 2f49345a..4878c550 100644
--- a/app/models/order.rb
+++ b/app/models/order.rb
@@ -1,6 +1,6 @@
+# encoding: utf-8
+#
class Order < ActiveRecord::Base
- extend ActiveSupport::Memoizable # Ability to cache method results. Use memoize :expensive_method
- acts_as_ordered :order => "ends" # easyier find of next or previous model
# Associations
has_many :order_articles, :dependent => :destroy
@@ -19,17 +19,14 @@ class Order < ActiveRecord::Base
validate :starts_before_ends, :include_articles
# Callbacks
- before_create do |order|
- order.created_by = User.current_user
- end
- after_update :update_price_of_group_orders
-
+ after_save :save_order_articles, :update_price_of_group_orders
+
# Finders
- named_scope :open, :conditions => {:state => 'open'}, :order => 'ends DESC'
- named_scope :finished, :conditions => "state = 'finished' OR state = 'closed'", :order => 'ends DESC'
- named_scope :finished_not_closed, :conditions => {:state => 'finished'}, :order => 'ends DESC'
- named_scope :closed, :conditions => {:state => 'closed'}, :order => 'ends DESC'
- named_scope :stockit, :conditions => {:supplier_id => 0}, :order => 'ends DESC'
+ scope :open, where(state: 'open').order('ends DESC')
+ scope :finished, where("orders.state = 'finished' OR orders.state = 'closed'").order('ends DESC')
+ scope :finished_not_closed, where(state: 'finished').order('ends DESC')
+ scope :closed, where(state: 'closed').order('ends DESC')
+ scope :stockit, where(supplier_id: 0).order('ends DESC')
def stockit?
supplier_id == 0
@@ -41,34 +38,24 @@ class Order < ActiveRecord::Base
def articles_for_ordering
if stockit?
- StockArticle.available.without_deleted(:include => :article_category,
+ # make sure to include those articles which are no longer available
+ # but which have already been ordered in this stock order
+ StockArticle.available.all(:include => :article_category,
:order => 'article_categories.name, articles.name').reject{ |a|
- a.quantity_available <= 0
+ a.quantity_available <= 0 and not a.ordered_in_order?(self)
}.group_by { |a| a.article_category.name }
else
- supplier.articles.available.without_deleted.group_by { |a| a.article_category.name }
+ supplier.articles.available.all.group_by { |a| a.article_category.name }
end
end
- # Fetch last orders from same supplier, to generate an article selection proposal
- def templates
- if stockit?
- Order.stockit :limit => 5
- else
- supplier.orders.finished :limit => 5
- end
- end
-
- # Create or destroy OrderArticle associations on create/update
+ # Save ids, and create/delete order_articles after successfully saved the order
def article_ids=(ids)
- # fetch selected articles
- articles_list = Article.find(ids)
- # create new order_articles
- (articles_list - articles).each { |article| order_articles.build(:article => article) }
- # delete old order_articles
- articles.reject { |article| articles_list.include?(article) }.each do |article|
- order_articles.detect { |order_article| order_article.article_id == article.id }.destroy
- end
+ @article_ids = ids
+ end
+
+ def article_ids
+ @article_ids ||= order_articles.map(&:article_id)
end
def open?
@@ -89,25 +76,26 @@ class Order < ActiveRecord::Base
# search GroupOrder of given Ordergroup
def group_order(ordergroup)
- group_orders.first :conditions => { :ordergroup_id => ordergroup.id }
+ group_orders.where(:ordergroup_id => ordergroup.id).first
end
-
+
# Returns OrderArticles in a nested Array, grouped by category and ordered by article name.
# The array has the following form:
# e.g: [["drugs",[teethpaste, toiletpaper]], ["fruits" => [apple, banana, lemon]]]
def articles_grouped_by_category
- order_articles.all(:include => [:article, :article_price], :order => 'articles.name').group_by { |a|
- a.article.article_category.name
- }.sort { |a, b| a[0] <=> b[0] }
+ @articles_grouped_by_category ||= order_articles.
+ includes([:article_price, :group_order_articles, :article => :article_category]).
+ order('articles.name').
+ group_by { |a| a.article.article_category.name }.
+ sort { |a, b| a[0] <=> b[0] }
end
- memoize :articles_grouped_by_category
def articles_sort_by_category
order_articles.all(:include => [:article], :order => 'articles.name').sort do |a,b|
a.article.article_category.name <=> b.article.article_category.name
end
end
-
+
# Returns the defecit/benefit for the foodcoop
# Requires a valid invoice, belonging to this order
#FIXME: Consider order.foodcoop_result
@@ -118,7 +106,7 @@ class Order < ActiveRecord::Base
groups_sum - invoice.net_amount
end
end
-
+
# Returns the all round price of a finished order
# :groups returns the sum of all GroupOrders
# :clear returns the price without tax, deposit and markup
@@ -127,25 +115,25 @@ class Order < ActiveRecord::Base
def sum(type = :gross)
total = 0
if type == :net || type == :gross || type == :fc
- for oa in order_articles.ordered.all(:include => [:article,:article_price])
+ for oa in order_articles.ordered.includes(:article, :article_price)
quantity = oa.units_to_order * oa.price.unit_quantity
case type
- when :net
- total += quantity * oa.price.price
- when :gross
- total += quantity * oa.price.gross_price
- when :fc
- total += quantity * oa.price.fc_price
+ when :net
+ total += quantity * oa.price.price
+ when :gross
+ total += quantity * oa.price.gross_price
+ when :fc
+ total += quantity * oa.price.fc_price
end
end
elsif type == :groups || type == :groups_without_markup
- for go in group_orders.all(:include => :group_order_articles)
- for goa in go.group_order_articles.all(:include => [:order_article])
+ for go in group_orders.includes(group_order_articles: {order_article: [:article, :article_price]})
+ for goa in go.group_order_articles
case type
- when :groups
- total += goa.result * goa.order_article.price.fc_price
- when :groups_without_markup
- total += goa.result * goa.order_article.price.gross_price
+ when :groups
+ total += goa.result * goa.order_article.price.fc_price
+ when :groups_without_markup
+ total += goa.result * goa.order_article.price.gross_price
end
end
end
@@ -158,23 +146,39 @@ class Order < ActiveRecord::Base
def finish!(user)
unless finished?
Order.transaction do
- # Update order_articles. Save the current article_price to keep price consistency
- # Also save results for each group_order_result
- order_articles.all(:include => :article).each do |oa|
- oa.update_attribute(:article_price, oa.article.article_prices.first)
- oa.group_order_articles.each { |goa| goa.save_results! }
- end
-
# set new order state (needed by notify_order_finished)
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
+ # Clean up
+ order_articles.all(:include => :article).each do |oa|
+ oa.update_attribute(:article_price, oa.article.article_prices.first)
+ oa.group_order_articles.each do |goa|
+ goa.save_results!
+ # Delete no longer required order-history (group_order_article_quantities) and
+ # TODO: Do we need articles, which aren't ordered? (units_to_order == 0 ?)
+ #goa.group_order_article_quantities.clear
+ end
+ end
+
+ # Update GroupOrder prices
+ group_orders.each(&:update_price!)
+
+ # Stats
+ ordergroups.each(&:update_stats!)
+
+ # Notifications
+ Resque.enqueue(UserNotifier, FoodsoftConfig.scope, 'finished_order', self.id)
end
end
end
-
+
# Sets order.status to 'close' and updates all Ordergroup.account_balances
def close!(user)
- raise "Bestellung wurde schon abgerechnet" if closed?
- transaction_note = "Bestellung: #{name}, bis #{ends.strftime('%d.%m.%Y')}"
+ raise I18n.t('orders.model.error_closed') if closed?
+ transaction_note = I18n.t('orders.model.notice_close', :name => name,
+ :ends => ends.strftime(I18n.t('date.formats.default')))
gos = group_orders.all(:include => :ordergroup) # Fetch group_orders
gos.each { |group_order| group_order.update_price! } # Update prices of group_orders
@@ -182,7 +186,7 @@ class Order < ActiveRecord::Base
transaction do # Start updating account balances
for group_order in gos
price = group_order.price * -1 # decrease! account balance
- group_order.ordergroup.add_financial_transaction(price, transaction_note, user)
+ group_order.ordergroup.add_financial_transaction!(price, transaction_note, user)
end
if stockit? # Decreases the quantity of stock_articles
@@ -196,18 +200,45 @@ class Order < ActiveRecord::Base
end
end
+ # Close the order directly, without automaticly updating ordergroups account balances
+ def close_direct!(user)
+ raise I18n.t('orders.model.error_closed') if closed?
+ update_attributes! state: 'closed', updated_by: user
+ end
+
protected
def starts_before_ends
- errors.add(:ends, "muss nach dem Bestellstart liegen (oder leer bleiben)") if (ends && starts && ends <= starts)
+ errors.add(:ends, I18n.t('articles.model.error_starts_before_ends')) if (ends && starts && ends <= starts)
end
def include_articles
- errors.add(:order_articles, "Es muss mindestens ein Artikel ausgewählt sein") if order_articles.empty?
+ errors.add(:articles, I18n.t('articles.model.error_nosel')) if article_ids.empty?
+ end
+
+ def save_order_articles
+ #self.articles = Article.find(article_ids) # This doesn't deletes the group_order_articles, belonging to order_articles,
+ # # see http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many
+ #
+ ## Ensure to delete also the group_order_articles, belonging to order_articles
+ ## This case is relevant, when removing articles from a running order
+ #goa_ids = GroupOrderArticle.where(group_order_id: group_order_ids).includes(:order_article).
+ # select { |goa| goa.order_article.nil? }.map(&:id)
+ #GroupOrderArticle.delete_all(id: goa_ids) unless goa_ids.empty?
+
+
+ # fetch selected articles
+ articles_list = Article.find(article_ids)
+ # create new order_articles
+ (articles_list - articles).each { |article| order_articles.create(:article => article) }
+ # delete old order_articles
+ articles.reject { |article| articles_list.include?(article) }.each do |article|
+ order_articles.detect { |order_article| order_article.article_id == article.id }.destroy
+ end
end
private
-
+
# Updates the "price" attribute of GroupOrders or GroupOrderResults
# This will be either the maximum value of a current order or the actual order value of a finished order.
def update_price_of_group_orders
@@ -216,18 +247,3 @@ class Order < ActiveRecord::Base
end
-# == Schema Information
-#
-# Table name: orders
-#
-# id :integer(4) not null, primary key
-# supplier_id :integer(4)
-# note :text
-# starts :datetime
-# ends :datetime
-# state :string(255) default("open")
-# lock_version :integer(4) default(0), not null
-# updated_by_user_id :integer(4)
-# foodcoop_result :decimal(8, 2)
-#
-
diff --git a/app/models/order_article.rb b/app/models/order_article.rb
index f64d5ba6..2d869ec5 100644
--- a/app/models/order_article.rb
+++ b/app/models/order_article.rb
@@ -1,6 +1,8 @@
# An OrderArticle represents a single Article that is part of an Order.
class OrderArticle < ActiveRecord::Base
+ attr_reader :update_current_price
+
belongs_to :order
belongs_to :article
belongs_to :article_price
@@ -8,9 +10,23 @@ class OrderArticle < ActiveRecord::Base
validates_presence_of :order_id, :article_id
validate :article_and_price_exist
+ validates_uniqueness_of :article_id, scope: :order_id
- named_scope :ordered, :conditions => "units_to_order >= 1"
+ scope :ordered, :conditions => "units_to_order >= 1"
+ before_create :init_from_balancing
+ after_destroy :update_ordergroup_prices
+
+ def self.sort_by_name(order_articles)
+ order_articles.sort { |a,b| a.article.name <=> b.article.name }
+ end
+
+ def self.sort_by_order_number(order_articles)
+ order_articles.sort do |a,b|
+ a.article.order_number.to_s.gsub(/[^[:digit:]]/, "").to_i <=>
+ b.article.order_number.to_s.gsub(/[^[:digit:]]/, "").to_i
+ end
+ end
# This method returns either the ArticlePrice or the Article
# The first will be set, when the the order is finished
@@ -77,50 +93,63 @@ class OrderArticle < ActiveRecord::Base
end
# Updates order_article and belongings during balancing process
- def update_article_and_price!(article_attributes, price_attributes, order_article_attributes, global_attribute)
+ def update_article_and_price!(order_article_attributes, article_attributes, price_attributes = nil)
OrderArticle.transaction do
+ # Updates self
+ self.update_attributes!(order_article_attributes)
+
# Updates article
article.update_attributes!(article_attributes)
- article.update_attributes!(price_attributes) if global_attribute
+ # Updates article_price belonging to current order article
+ if price_attributes.present?
+ article_price.attributes = price_attributes
+ if article_price.changed?
+ # Updates also price attributes of article if update_current_price is selected
+ if update_current_price
+ article.update_attributes!(price_attributes)
+ self.article_price = article.article_prices.first # Assign new created article price to order article
+ else
+ # Creates a new article_price if neccessary
+ # Set created_at timestamp to order ends, to make sure the current article price isn't changed
+ create_article_price!(price_attributes.merge(created_at: order.ends)) and save
+ end
- article_price.attributes = price_attributes
- if article_price.changed?
- # Creates a new article_price if neccessary
- price = build_article_price(price_attributes)
- price.created_at = order.ends
- price.save!
-
- # Updates ordergroup values
- group_order_articles.each { |goa| goa.group_order.update_price! }
+ # Updates ordergroup values
+ update_ordergroup_prices
+ end
end
-
-
- # Updates units_to_order
- self.attributes = order_article_attributes
- self.save!
end
end
+ def update_current_price=(value)
+ @update_current_price = (value == true or value == '1') ? true : false
+ end
+
+ # Units missing for the next full unit_quantity of the article
+ def missing_units
+ units = article.unit_quantity - ((quantity % article.unit_quantity) + tolerance)
+ units = 0 if units < 0
+ units
+ end
+
private
def article_and_price_exist
- errors.add(:article, "muss angegeben sein und einen aktuellen Preis haben") if !(article = Article.find(article_id)) || article.fc_price.nil?
+ errors.add(:article, I18n.t('model.order_article.error_price')) if !(article = Article.find(article_id)) || article.fc_price.nil?
+ end
+
+ # Associate with current article price if created in a finished order
+ def init_from_balancing
+ if order.present? and order.finished?
+ self.article_price = article.article_prices.first
+ self.units_to_order = 1
+ end
+ end
+
+ def update_ordergroup_prices
+ group_order_articles.each { |goa| goa.group_order.update_price! }
end
end
-# == Schema Information
-#
-# Table name: order_articles
-#
-# id :integer(4) not null, primary key
-# order_id :integer(4) default(0), not null
-# article_id :integer(4) default(0), not null
-# quantity :integer(4) default(0), not null
-# tolerance :integer(4) default(0), not null
-# units_to_order :integer(4) default(0), not null
-# lock_version :integer(4) default(0), not null
-# article_price_id :integer(4)
-#
-
diff --git a/app/models/order_comment.rb b/app/models/order_comment.rb
index 98126d74..1b0b0e39 100644
--- a/app/models/order_comment.rb
+++ b/app/models/order_comment.rb
@@ -4,16 +4,6 @@ class OrderComment < ActiveRecord::Base
belongs_to :user
validates_presence_of :order_id, :user_id, :text
+ validates_length_of :text, :minimum => 3
end
-# == Schema Information
-#
-# Table name: order_comments
-#
-# id :integer(4) not null, primary key
-# order_id :integer(4)
-# user_id :integer(4)
-# text :text
-# created_at :datetime
-#
-
diff --git a/app/models/ordergroup.rb b/app/models/ordergroup.rb
index aee429f7..5b9c6f19 100644
--- a/app/models/ordergroup.rb
+++ b/app/models/ordergroup.rb
@@ -1,18 +1,21 @@
+# encoding: utf-8
+#
# Ordergroups can order, they are "children" of the class Group
#
# Ordergroup have the following attributes, in addition to Group
# * account_balance (decimal)
-# * account_updated (datetime)
class Ordergroup < Group
- acts_as_paranoid # Avoid deleting the ordergroup for consistency of order-results
- extend ActiveSupport::Memoizable # Ability to cache method results. Use memoize :expensive_method
+
+ APPLE_MONTH_AGO = 6 # How many month back we will count tasks and orders sum
+
serialize :stats
- has_many :financial_transactions, :order => "created_on DESC"
+ has_many :financial_transactions
has_many :group_orders
has_many :orders, :through => :group_orders
- validates_numericality_of :account_balance, :message => 'ist keine gültige Zahl'
+ validates_numericality_of :account_balance, :message => I18n.t('ordergroups.model.invalid_balance')
+ validate :uniqueness_of_name, :uniqueness_of_members
after_create :update_stats!
@@ -24,11 +27,11 @@ class Ordergroup < Group
end
def value_of_open_orders(exclude = nil)
- group_orders.open.reject{|go| go == exclude}.collect(&:price).sum
+ group_orders.in_open_orders.reject{|go| go == exclude}.collect(&:price).sum
end
def value_of_finished_orders(exclude = nil)
- group_orders.finished.reject{|go| go == exclude}.collect(&:price).sum
+ group_orders.in_finished_orders.reject{|go| go == exclude}.collect(&:price).sum
end
# Returns the available funds for this order group (the account_balance minus price of all non-closed GroupOrders of this group).
@@ -36,25 +39,29 @@ class Ordergroup < Group
def get_available_funds(exclude = nil)
account_balance - value_of_open_orders(exclude) - value_of_finished_orders(exclude)
end
- memoize :get_available_funds
# Creates a new FinancialTransaction for this Ordergroup and updates the account_balance accordingly.
# Throws an exception if it fails.
- def add_financial_transaction(amount, note, user)
+ def add_financial_transaction!(amount, note, user)
transaction do
- trans = FinancialTransaction.new(:ordergroup => self, :amount => amount, :note => note, :user => user)
- trans.save!
- self.account_balance += trans.amount
- self.account_updated = trans.created_on
+ t = FinancialTransaction.new(:ordergroup => self, :amount => amount, :note => note, :user => user)
+ t.save!
+ self.account_balance = financial_transactions.sum('amount')
save!
- notify_negative_balance(trans)
+ # Notify only when order group had a positive balance before the last transaction:
+ if t.amount < 0 && self.account_balance < 0 && self.account_balance - t.amount >= 0
+ Resque.enqueue(UserNotifier, FoodsoftConfig.scope, 'negative_balance', self.id, t.id)
+ end
end
end
def update_stats!
- time = 6.month.ago
- jobs = users.collect { |u| u.tasks.done.sum('duration', :conditions => ["updated_on > ?", time]) }.sum
- orders_sum = group_orders.select { |go| !go.order.ends.nil? && go.order.ends > time }.collect(&:price).sum
+ # Get hours for every job of each user in period
+ jobs = users.sum { |u| u.tasks.done.sum(:duration, :conditions => ["updated_on > ?", APPLE_MONTH_AGO.month.ago]) }
+ # Get group_order.price for every finished order in this period
+ orders_sum = group_orders.includes(:order).merge(Order.finished).where('orders.ends >= ?', APPLE_MONTH_AGO.month.ago).sum(:price)
+
+ @readonly = false # Dirty hack, avoid getting RecordReadOnly exception when called in task after_save callback. A rails bug?
update_attribute(:stats, {:jobs_size => jobs, :orders_sum => orders_sum})
end
@@ -68,53 +75,56 @@ class Ordergroup < Group
((avg_jobs_per_euro / Ordergroup.avg_jobs_per_euro) * 100).to_i rescue 0
end
+ # If the the option stop_ordering_under is set, the ordergroup is only allowed to participate in an order,
+ # when the apples value is above the configured amount.
+ # The restriction can be deactivated for each ordergroup.
+ # Only ordergroups, which have participated in more than 5 orders in total and more than 2 orders in apple time period
+ def not_enough_apples?
+ FoodsoftConfig[:stop_ordering_under].present? and
+ !ignore_apple_restriction and
+ apples < FoodsoftConfig[:stop_ordering_under] and
+ group_orders.count > 5 and
+ group_orders.joins(:order).merge(Order.finished).where('orders.ends >= ?', APPLE_MONTH_AGO.month.ago).count > 2
+ end
+
# Global average
def self.avg_jobs_per_euro
- stats = Ordergroup.all.collect(&:stats)
- stats.collect {|s| s[:jobs_size].to_f }.sum / stats.collect {|s| s[:orders_sum].to_f }.sum
+ stats = Ordergroup.pluck(:stats)
+ stats.sum {|s| s[:jobs_size].to_f } / stats.sum {|s| s[:orders_sum].to_f }
+ end
+
+ def account_updated
+ financial_transactions.last.try(:created_on) || created_on
end
private
-
- # If this order group's account balance is made negative by the given/last transaction,
- # a message is sent to all users who have enabled notification.
- def notify_negative_balance(transaction)
- # Notify only when order group had a positive balance before the last transaction:
- if (transaction.amount < 0 && self.account_balance < 0 && self.account_balance - transaction.amount >= 0)
- for user in users
- Mailer.deliver_negative_balance(user,transaction) if user.settings["notify.negativeBalance"] == '1'
- end
+
+ # Make sure, that a user can only be in one ordergroup
+ def uniqueness_of_members
+ users.each do |user|
+ errors.add :user_tokens, I18n.t('ordergroups.model.error_single_group', :user => user.nick) if user.groups.where(:type => 'Ordergroup').size > 1
+ end
+ end
+
+ # Make sure, the name is uniq, add usefull message if uniq group is already deleted
+ def uniqueness_of_name
+ id = new_record? ? '' : self.id
+ group = Ordergroup.with_deleted.where('groups.id != ? AND groups.name = ?', id, name).first
+ if group.present?
+ message = group.deleted? ? :taken_with_deleted : :taken
+ errors.add :name, message
+ end
+ end
+
+ # Make sure, the name is uniq, add usefull message if uniq group is already deleted
+ def uniqueness_of_name
+ id = new_record? ? '' : self.id
+ group = Ordergroup.where('groups.id != ? AND groups.name = ?', id, name).first
+ if group.present?
+ message = group.deleted? ? :taken_with_deleted : :taken
+ errors.add :name, message
end
end
end
-# == Schema Information
-#
-# Table name: groups
-#
-# id :integer(4) not null, primary key
-# type :string(255) default(""), not null
-# name :string(255) default(""), not null
-# description :string(255)
-# account_balance :decimal(8, 2) default(0.0), not null
-# account_updated :datetime
-# created_on :datetime not null
-# role_admin :boolean(1) default(FALSE), not null
-# role_suppliers :boolean(1) default(FALSE), not null
-# role_article_meta :boolean(1) default(FALSE), not null
-# role_finance :boolean(1) default(FALSE), not null
-# role_orders :boolean(1) default(FALSE), not null
-# weekly_task :boolean(1) default(FALSE)
-# weekday :integer(4)
-# task_name :string(255)
-# task_description :string(255)
-# task_required_users :integer(4) default(1)
-# deleted_at :datetime
-# contact_person :string(255)
-# contact_phone :string(255)
-# contact_address :string(255)
-# stats :text
-# task_duration :integer(4) default(1)
-#
-
diff --git a/app/models/page.rb b/app/models/page.rb
index 65b55e28..3dfba7aa 100644
--- a/app/models/page.rb
+++ b/app/models/page.rb
@@ -1,9 +1,11 @@
class Page < ActiveRecord::Base
+ include ActsAsTree
belongs_to :user, :foreign_key => 'updated_by'
- acts_as_versioned :version_column => :lock_version, :limit => 20
- self.non_versioned_columns += ['permalink', 'created_at', 'title']
+ acts_as_versioned version_column: :lock_version, limit: 20
+ self.non_versioned_columns += %w(permalink created_at title)
+
acts_as_tree :order => "title"
attr_accessor :old_title # Save title to create redirect page when editing title
@@ -11,12 +13,12 @@ class Page < ActiveRecord::Base
validates_presence_of :title, :body
validates_uniqueness_of :permalink, :title
- before_validation_on_create :set_permalink
- before_validation_on_update :update_permalink
+ before_validation :set_permalink, :on => :create
+ before_validation :update_permalink, :on => :update
after_update :create_redirect
- named_scope :non_redirected, :conditions => {:redirect => nil}
- named_scope :no_parent, :conditions => {:parent_id => nil}
+ scope :non_redirected, :conditions => {:redirect => nil}
+ scope :no_parent, :conditions => {:parent_id => nil}
def self.permalink(title)
title.gsub(/[\/\.,;@\s]/, "_").gsub(/[\"\']/, "")
@@ -45,26 +47,10 @@ class Page < ActiveRecord::Base
unless old_title.blank?
Page.create :redirect => id,
:title => old_title,
- :body => "Weiterleitung auf [[#{title}]]..",
+ :body => I18n.t('model.page.redirect', :title => title),
:permalink => Page.permalink(old_title),
:updated_by => updated_by
end
end
end
-# == Schema Information
-#
-# Table name: pages
-#
-# id :integer(4) not null, primary key
-# title :string(255)
-# body :text
-# permalink :string(255)
-# lock_version :integer(4) default(0)
-# updated_by :integer(4)
-# redirect :integer(4)
-# parent_id :integer(4)
-# created_at :datetime
-# updated_at :datetime
-#
-
diff --git a/app/models/shared_article.rb b/app/models/shared_article.rb
index 3606e77c..777b7f77 100644
--- a/app/models/shared_article.rb
+++ b/app/models/shared_article.rb
@@ -1,33 +1,26 @@
-# == Schema Information
-# Schema version: 20090102171850
-#
-# Table name: articles
-#
-# id :integer(4) not null, primary key
-# name :string(255) not null
-# supplier_id :integer(4) not null
-# number :string(255)
-# note :string(255)
-# manufacturer :string(255)
-# origin :string(255)
-# unit :string(255)
-# price :decimal(8, 2) default(0.0), not null
-# tax :decimal(3, 1) default(7.0), not null
-# deposit :decimal(8, 2) default(0.0), not null
-# unit_quantity :decimal(4, 1) default(1.0), not null
-# scale_quantity :decimal(4, 2)
-# scale_price :decimal(8, 2)
-# created_on :datetime
-# updated_on :datetime
-# list :string(255)
-#
-
class SharedArticle < ActiveRecord::Base
-
+
# connect to database from sharedLists-Application
- SharedArticle.establish_connection(Foodsoft.config[:shared_lists])
+ SharedArticle.establish_connection(FoodsoftConfig[:shared_lists])
# set correct table_name in external DB
- set_table_name :articles
-
+ self.table_name = 'articles'
+
belongs_to :shared_supplier, :foreign_key => :supplier_id
+
+ def build_new_article
+ shared_supplier.supplier.articles.build(
+ :name => name,
+ :unit => unit,
+ :note => note,
+ :manufacturer => manufacturer,
+ :origin => origin,
+ :price => price,
+ :tax => tax,
+ :deposit => deposit,
+ :unit_quantity => unit_quantity,
+ :order_number => number,
+ # convert to db-compatible-string
+ :shared_updated_on => updated_on.to_formatted_s(:db)
+ )
+ end
end
diff --git a/app/models/shared_supplier.rb b/app/models/shared_supplier.rb
index af4f770f..fa1e582a 100644
--- a/app/models/shared_supplier.rb
+++ b/app/models/shared_supplier.rb
@@ -1,36 +1,12 @@
class SharedSupplier < ActiveRecord::Base
# connect to database from sharedLists-Application
- SharedSupplier.establish_connection(Foodsoft.config[:shared_lists])
+ SharedSupplier.establish_connection(FoodsoftConfig[:shared_lists])
# set correct table_name in external DB
- set_table_name :suppliers
-
-
+ self.table_name = 'suppliers'
+
has_one :supplier
has_many :shared_articles, :foreign_key => :supplier_id
end
-# == Schema Information
-#
-# Table name: suppliers
-#
-# id :integer(4) not null, primary key
-# name :string(255) not null
-# address :string(255) not null
-# phone :string(255) not null
-# phone2 :string(255)
-# fax :string(255)
-# email :string(255)
-# url :string(255)
-# delivery_days :string(255)
-# note :string(255)
-# created_on :datetime
-# updated_on :datetime
-# lists :string(255)
-# bnn_sync :boolean(1) default(FALSE)
-# bnn_host :string(255)
-# bnn_user :string(255)
-# bnn_password :string(255)
-#
-
diff --git a/app/models/stock_article.rb b/app/models/stock_article.rb
index 7e2924c0..0124219a 100644
--- a/app/models/stock_article.rb
+++ b/app/models/stock_article.rb
@@ -1,7 +1,9 @@
+# encoding: utf-8
class StockArticle < Article
+
has_many :stock_changes
- named_scope :available, :conditions => "quantity > 0"
+ scope :available, -> { undeleted.where'quantity > 0' }
before_destroy :check_quantity
@@ -11,25 +13,24 @@ class StockArticle < Article
end
# Check for unclosed orders and substract its ordered quantity
- def quantity_available(exclude_order = nil)
- available = quantity
- for order in Order.stockit.all(:conditions => "state = 'open' OR state = 'finished'")
- unless order == exclude_order
- order_article = order.order_articles.first(:conditions => {:article_id => id})
- available -= order_article.units_to_order if order_article
- end
- end
- available
+ def quantity_available
+ quantity - OrderArticle.where(article_id: id).
+ joins(:order).where("orders.state = 'open' OR orders.state = 'finished'").sum(:units_to_order)
end
def self.stock_value
available.collect { |a| a.quantity * a.gross_price }.sum
end
+ def mark_as_deleted
+ check_quantity
+ super
+ end
+
protected
def check_quantity
- raise "#{name} kann nicht gelöscht werden. Der Lagerbestand ist nicht null." unless quantity == 0
+ raise I18n.t('stockit.check.not_empty', :name => name) unless quantity == 0
end
# Overwrite Price history of Article. For StockArticles isn't it necessary.
@@ -38,29 +39,3 @@ class StockArticle < Article
end
end
-# == Schema Information
-#
-# Table name: articles
-#
-# id :integer(4) not null, primary key
-# name :string(255) default(""), not null
-# supplier_id :integer(4) default(0), not null
-# article_category_id :integer(4) default(0), not null
-# unit :string(255) default(""), not null
-# note :string(255)
-# availability :boolean(1) default(TRUE), not null
-# manufacturer :string(255)
-# origin :string(255)
-# shared_updated_on :datetime
-# price :decimal(8, 2)
-# tax :float
-# deposit :decimal(8, 2) default(0.0)
-# unit_quantity :integer(4) default(1), not null
-# order_number :string(255)
-# created_at :datetime
-# updated_at :datetime
-# deleted_at :datetime
-# type :string(255)
-# quantity :integer(4) default(0)
-#
-
diff --git a/app/models/stock_change.rb b/app/models/stock_change.rb
index 7797dc11..6a7adc75 100644
--- a/app/models/stock_change.rb
+++ b/app/models/stock_change.rb
@@ -16,16 +16,3 @@ class StockChange < ActiveRecord::Base
end
end
-# == Schema Information
-#
-# Table name: stock_changes
-#
-# id :integer(4) not null, primary key
-# delivery_id :integer(4)
-# order_id :integer(4)
-# stock_article_id :integer(4)
-# quantity :integer(4) default(0)
-# created_at :datetime
-# stock_taking_id :integer(4)
-#
-
diff --git a/app/models/stock_taking.rb b/app/models/stock_taking.rb
index a5c6b335..0348459c 100644
--- a/app/models/stock_taking.rb
+++ b/app/models/stock_taking.rb
@@ -12,13 +12,3 @@ class StockTaking < ActiveRecord::Base
end
end
-# == Schema Information
-#
-# Table name: stock_takings
-#
-# id :integer(4) not null, primary key
-# date :date
-# note :text
-# created_at :datetime
-#
-
diff --git a/app/models/supplier.rb b/app/models/supplier.rb
index b1768bfe..557cd4e4 100644
--- a/app/models/supplier.rb
+++ b/app/models/supplier.rb
@@ -1,7 +1,7 @@
+# encoding: utf-8
class Supplier < ActiveRecord::Base
- acts_as_paranoid # Avoid deleting the supplier for consistency of order-results
- has_many :articles, :dependent => :destroy, :conditions => {:type => nil},
+ has_many :articles, :conditions => {:type => nil},
:include => [:article_category], :order => 'article_categories.name, articles.name'
has_many :stock_articles, :include => [:article_category], :order => 'article_categories.name, articles.name'
has_many :orders
@@ -9,13 +9,18 @@ class Supplier < ActiveRecord::Base
has_many :invoices
belongs_to :shared_supplier # for the sharedLists-App
- attr_accessible :name, :address, :phone, :phone2, :fax, :email, :url, :contact_person, :customer_number, :delivery_days, :order_howto, :note, :shared_supplier_id, :min_order_quantity
-
- validates_length_of :name, :in => 4..30
- validates_uniqueness_of :name
+ attr_accessible :name, :address, :phone, :phone2, :fax, :email, :url, :contact_person, :customer_number,
+ :delivery_days, :order_howto, :note, :shared_supplier_id, :min_order_quantity
+ validates :name, :presence => true, :length => { :in => 4..30 }
+ validates :phone, :presence => true, :length => { :in => 8..20 }
+ validates :address, :presence => true, :length => { :in => 8..50 }
+ validates_length_of :order_howto, :note, maximum: 250
validates_length_of :phone, :in => 8..20
validates_length_of :address, :in => 8..50
+ validate :uniqueness_of_name
+
+ scope :undeleted, -> { where(deleted_at: nil) }
# sync all articles with the external database
# returns an array with articles(and prices), which should be updated (to use in a form)
@@ -23,7 +28,7 @@ class Supplier < ActiveRecord::Base
def sync_all
updated_articles = Array.new
outlisted_articles = Array.new
- for article in articles.without_deleted
+ for article in articles.undeleted
# try to find the associated shared_article
shared_article = article.shared_article
@@ -61,27 +66,28 @@ class Supplier < ActiveRecord::Base
end
return [updated_articles, outlisted_articles]
end
+
+ def deleted?
+ deleted_at.present?
+ end
+
+ def mark_as_deleted
+ transaction do
+ update_column :deleted_at, Time.now
+ articles.each(&:mark_as_deleted)
+ end
+ end
+
+ protected
+
+ # Make sure, the name is uniq, add usefull message if uniq group is already deleted
+ def uniqueness_of_name
+ id = new_record? ? '' : self.id
+ supplier = Supplier.where('suppliers.id != ? AND suppliers.name = ?', id, name).first
+ if supplier.present?
+ message = supplier.deleted? ? :taken_with_deleted : :taken
+ errors.add :name, message
+ end
+ end
end
-# == Schema Information
-#
-# Table name: suppliers
-#
-# id :integer(4) not null, primary key
-# name :string(255) default(""), not null
-# address :string(255) default(""), not null
-# phone :string(255) default(""), not null
-# phone2 :string(255)
-# fax :string(255)
-# email :string(255)
-# url :string(255)
-# contact_person :string(255)
-# customer_number :string(255)
-# delivery_days :string(255)
-# order_howto :string(255)
-# note :string(255)
-# shared_supplier_id :integer(4)
-# min_order_quantity :string(255)
-# deleted_at :datetime
-#
-
diff --git a/app/models/task.rb b/app/models/task.rb
index f32e6ebd..64c5ff20 100644
--- a/app/models/task.rb
+++ b/app/models/task.rb
@@ -3,18 +3,49 @@ class Task < ActiveRecord::Base
has_many :users, :through => :assignments
belongs_to :workgroup
- named_scope :non_group, :conditions => { :workgroup_id => nil, :done => false }
- named_scope :done, :conditions => {:done => true}, :order => "due_date DESC"
- named_scope :upcoming, lambda { |*args| {:conditions => ["done = 0 AND due_date = ?", (args.first || 7.days.from_now)]} }
-
+ scope :non_group, where(workgroup_id: nil, done: false)
+ scope :done, where(done: true)
+ scope :undone, where(done: false)
+
+ attr_accessor :current_user_id
+
# form will send user in string. responsibilities will added later
attr_protected :users
-
- validates_length_of :name, :minimum => 3
- validates_numericality_of :duration, :required_users, :only_integer => true, :greater_than_or_equal_to => 1
+
+ validates :name, :presence => true, :length => { :minimum => 3 }
+ validates :required_users, :presence => true
+ validates_numericality_of :duration, :required_users, :only_integer => true, :greater_than => 0
+ validates_length_of :description, maximum: 250
after_save :update_ordergroup_stats
-
+
+ # Find all tasks, for which the current user should be responsible
+ # but which aren't accepted yet
+ def self.unaccepted_tasks_for(user)
+ user.tasks.undone.where(assignments: {accepted: false})
+ end
+
+ # Find all accepted tasks, which aren't done
+ def self.accepted_tasks_for(user)
+ user.tasks.undone.where(assignments: {accepted: true})
+ end
+
+
+ # find all tasks in the next week (or another number of days)
+ def self.next_assigned_tasks_for(user, number = 7)
+ user.tasks.undone.where(assignments: {accepted: true}).
+ where(["tasks.due_date >= ? AND tasks.due_date <= ?", Time.now, number.days.from_now])
+ end
+
+ # count tasks with not enough responsible people
+ # tasks for groups the user is not a member are ignored
+ def self.unassigned_tasks_for(user)
+ undone.includes(:assignments, workgroup: :memberships).select do |task|
+ !task.enough_users_assigned? and
+ (!task.workgroup or task.workgroup.memberships.detect { |m| m.user_id == user.id })
+ end
+ end
+
def is_assigned?(user)
self.assignments.detect {|ass| ass.user_id == user.id }
end
@@ -24,33 +55,33 @@ class Task < ActiveRecord::Base
end
def enough_users_assigned?
- assignments.find_all_by_accepted(true).size >= required_users ? true : false
+ assignments.to_a.count(&:accepted) >= required_users ? true : false
end
-
- # extracts nicknames from a comma seperated string
+
+ def still_required_users
+ required_users - assignments.to_a.count(&:accepted)
+ end
+
+ # Get users from comma seperated ids
# and makes the users responsible for the task
- # TODO: check for uniqueness
# TODO: check for maximal number of users
- def user_list=(string)
- @user_list = string.split(%r{,\s*})
- new_users = @user_list - users.collect(&:nick)
- old_users = users.reject { |user| @user_list.include?(user.nick) }
-
- logger.debug "New users: #{new_users}"
- logger.debug "Old users: #{old_users}"
+ def user_list=(ids)
+ list = ids.split(",").map(&:to_i)
+ new_users = (list - users.collect(&:id)).uniq
+ old_users = users.reject { |user| list.include?(user.id) }
self.class.transaction do
# delete old assignments
if old_users.any?
- assignments.find(:all, :conditions => ["user_id IN (?)", old_users.collect(&:id)]).each(&:destroy)
+ assignments.where(user_id: old_users.map(&:id)).each(&:destroy)
end
# create new assignments
- new_users.each do |nick|
- user = User.find_by_nick(nick)
+ new_users.each do |id|
+ user = User.find(id)
if user.blank?
errors.add(:user_list)
else
- if user == User.current_user
+ if id == current_user_id.to_i
# current_user will accept, when he puts himself to the list of users
self.assignments.build :user => user, :accepted => true
else
@@ -63,33 +94,11 @@ class Task < ActiveRecord::Base
end
def user_list
- @user_list ||= users.collect(&:nick).join(", ")
+ @user_list ||= users.collect(&:id).join(", ")
end
- private
-
- def update_ordergroup_stats
- if done
- users.each { |u| u.ordergroup.update_stats! if u.ordergroup }
- end
+ def update_ordergroup_stats(user_ids = self.user_ids)
+ Ordergroup.joins(:users).where(users: {id: user_ids}).each(&:update_stats!)
end
end
-# == Schema Information
-#
-# Table name: tasks
-#
-# id :integer(4) not null, primary key
-# name :string(255) default(""), not null
-# description :string(255)
-# due_date :date
-# done :boolean(1) default(FALSE)
-# workgroup_id :integer(4)
-# assigned :boolean(1) default(FALSE)
-# created_on :datetime not null
-# updated_on :datetime not null
-# required_users :integer(4) default(1)
-# weekly :boolean(1)
-# duration :integer(4) default(1)
-#
-
diff --git a/app/models/user.rb b/app/models/user.rb
index 3011d2a4..359bf51c 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
require 'digest/sha1'
# specific user rights through memberships (see Group)
class User < ActiveRecord::Base
@@ -5,7 +7,11 @@ class User < ActiveRecord::Base
has_many :memberships, :dependent => :destroy
has_many :groups, :through => :memberships
- has_one :ordergroup, :through => :memberships, :source => :group, :class_name => "Ordergroup"
+ #has_one :ordergroup, :through => :memberships, :source => :group, :class_name => "Ordergroup"
+ def ordergroup
+ Ordergroup.joins(:memberships).where(memberships: {user_id: self.id}).first
+ end
+
has_many :workgroups, :through => :memberships, :source => :group, :class_name => "Workgroup"
has_many :assignments, :dependent => :destroy
has_many :tasks, :through => :assignments
@@ -16,7 +22,7 @@ class User < ActiveRecord::Base
attr_accessor :password, :setting_attributes
validates_presence_of :nick, :email
- validates_presence_of :password_hash, :message => "Password is required."
+ validates_presence_of :password, :on => :create
validates_length_of :nick, :in => 2..25
validates_uniqueness_of :nick, :case_sensitive => false
validates_format_of :email, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
@@ -38,13 +44,13 @@ class User < ActiveRecord::Base
# returns the User-settings and the translated description
def self.setting_keys
{
- "notify.orderFinished" => 'Informier mich über meine Bestellergebnisse (nach Ende der Bestellung).',
- "notify.negativeBalance" => 'Informiere mich, falls meine Bestellgruppe ins Minus rutscht.',
- "notify.upcoming_tasks" => 'Erinnere mich an anstehende Aufgaben.',
- "messages.sendAsEmail" => 'Bekomme Nachrichten als Emails.',
- "profile.phoneIsPublic" => 'Telefon ist für Mitglieder sichtbar',
- "profile.emailIsPublic" => 'E-Mail ist für Mitglieder sichtbar',
- "profile.nameIsPublic" => 'Name ist für Mitglieder sichtbar'
+ "notify.orderFinished" => I18n.t('model.user.notify.order_finished'),
+ "notify.negativeBalance" => I18n.t('model.user.notify.negative_balance'),
+ "notify.upcoming_tasks" => I18n.t('model.user.notify.upcoming_tasks'),
+ "messages.sendAsEmail" => I18n.t('model.user.notify.send_as_email'),
+ "profile.phoneIsPublic" => I18n.t('model.user.notify.phone_is_public'),
+ "profile.emailIsPublic" => I18n.t('model.user.notify.email_is_public'),
+ "profile.nameIsPublic" => I18n.t('model.user.notify.name_is_public')
}
end
# retuns the default setting for a NEW user
@@ -71,8 +77,8 @@ class User < ActiveRecord::Base
[first_name, last_name].join(" ")
end
- def ordergroup_name
- ordergroup.name if ordergroup
+ def receive_email?
+ settings['messages.sendAsEmail'] == "1" && email.present?
end
# Sets the user's password. It will be stored encrypted along with a random salt.
@@ -126,47 +132,9 @@ class User < ActiveRecord::Base
end
def ordergroup_name
- ordergroup ? ordergroup.name : "keine Bestellgruppe"
+ ordergroup ? ordergroup.name : I18n.t('model.user.no_ordergroup')
end
- # Find all tasks, for which the current user should be responsible
- # but which aren't accepted yet
- def unaccepted_tasks
- # this doesn't work. Produces "undefined method", when later use task.users... Rails Bug?
- # self.tasks.find :all, :conditions => ["accepted = ?", false], :order => "due_date DESC"
- Task.find_by_sql ["SELECT t.* FROM tasks t, assignments a, users u
- WHERE u.id = a.user_id
- AND t.id = a.task_id
- AND u.id = ?
- AND a.accepted = ?
- AND t.done = ?
- ORDER BY t.due_date ASC", self.id, false, false]
- end
-
- # Find all accepted tasks, which aren't done
- def accepted_tasks
- Task.find_by_sql ["SELECT t.* FROM tasks t, assignments a, users u
- WHERE u.id = a.user_id
- AND t.id = a.task_id
- AND u.id = ?
- AND a.accepted = ?
- AND t.done = ?
- ORDER BY t.due_date ASC", self.id, true, false]
- end
-
- # find all tasks in the next week (or another number of days)
- def next_tasks(number = 7)
- Task.find_by_sql ["SELECT t.* FROM tasks t, assignments a, users u
- WHERE u.id = a.user_id
- AND t.id = a.task_id
- AND u.id = ?
- AND t.due_date >= ?
- AND t.due_date <= ?
- AND t.done = ?
- AND a.accepted = ?
- ORDER BY t.due_date ASC", self.id, Time.now, number.days.from_now, false, true]
- end
-
# returns true if user is a member of a given group
def member_of?(group)
group.users.exists?(self.id)
@@ -177,23 +145,18 @@ class User < ActiveRecord::Base
self.groups.find(:all, :conditions => {:type => ""})
end
+ def self.authenticate(nick, password)
+ user = find_by_nick(nick)
+ if user && user.has_password(password)
+ user
+ else
+ nil
+ end
+ end
+
+ def token_attributes
+ {:id => id, :name => "#{nick} (#{ordergroup.try(:name)})"}
+ end
+
end
-# == Schema Information
-#
-# Table name: users
-#
-# id :integer(4) not null, primary key
-# nick :string(255) default(""), not null
-# password_hash :string(255) default(""), not null
-# password_salt :string(255) default(""), not null
-# first_name :string(255) default(""), not null
-# last_name :string(255) default(""), not null
-# email :string(255) default(""), not null
-# phone :string(255)
-# created_on :datetime not null
-# reset_password_token :string(255)
-# reset_password_expires :datetime
-# last_login :datetime
-#
-
diff --git a/app/models/workgroup.rb b/app/models/workgroup.rb
index d956066b..6c93d693 100644
--- a/app/models/workgroup.rb
+++ b/app/models/workgroup.rb
@@ -1,16 +1,22 @@
+# encoding: utf-8
class Workgroup < Group
has_many :tasks
# returns all non-finished tasks
has_many :open_tasks, :class_name => 'Task', :conditions => ['done = ?', false], :order => 'due_date ASC'
+ validates_uniqueness_of :name
validates_presence_of :task_name, :weekday, :task_required_users, :next_weekly_tasks_number,
- :if => :weekly_task
+ :if => :weekly_task
validates_numericality_of :next_weekly_tasks_number, :greater_than => 0, :less_than => 21, :only_integer => true,
- :if => :weekly_task
+ :if => :weekly_task
+ validates_length_of :task_description, maximum: 250
+ validate :last_admin_on_earth, :on => :update
+ before_destroy :check_last_admin_group
def self.weekdays
- [["Montag", "1"], ["Dienstag", "2"], ["Mittwoch","3"],["Donnerstag","4"],["Freitag","5"],["Samstag","6"],["Sonntag","0"]]
+ days = I18n.t('date.day_names')
+ (0..days.length-1).map {|i| [days[i], i.to_s]}
end
# Returns an Array with date-objects to represent the next weekly-tasks
@@ -44,35 +50,23 @@ class Workgroup < Group
:weekly => true
}
end
+
+ protected
+
+ # Check before destroy a group, if this is the last group with admin role
+ def check_last_admin_group
+ if role_admin && Workgroup.where(:role_admin => true).size == 1
+ raise I18n.t('workgroups.error_last_admin_group')
+ end
+ end
+
+ # add validation check on update
+ # Return an error if this is the last group with admin role and role_admin should set to false
+ def last_admin_on_earth
+ if !role_admin && !Workgroup.where('role_admin = ? AND id != ?', true, id).exists?
+ errors.add(:role_admin, I18n.t('workgroups.error_last_admin_role'))
+ end
+ end
end
-# == Schema Information
-#
-# Table name: groups
-#
-# id :integer(4) not null, primary key
-# type :string(255) default(""), not null
-# name :string(255) default(""), not null
-# description :string(255)
-# account_balance :decimal(8, 2) default(0.0), not null
-# account_updated :datetime
-# created_on :datetime not null
-# role_admin :boolean(1) default(FALSE), not null
-# role_suppliers :boolean(1) default(FALSE), not null
-# role_article_meta :boolean(1) default(FALSE), not null
-# role_finance :boolean(1) default(FALSE), not null
-# role_orders :boolean(1) default(FALSE), not null
-# weekly_task :boolean(1) default(FALSE)
-# weekday :integer(4)
-# task_name :string(255)
-# task_description :string(255)
-# task_required_users :integer(4) default(1)
-# deleted_at :datetime
-# contact_person :string(255)
-# contact_phone :string(255)
-# contact_address :string(255)
-# stats :text
-# task_duration :integer(4) default(1)
-#
-
diff --git a/app/views/admin/base/index.html.haml b/app/views/admin/base/index.html.haml
index a26518fb..fbe63c09 100644
--- a/app/views/admin/base/index.html.haml
+++ b/app/views/admin/base/index.html.haml
@@ -1,45 +1,43 @@
-- title "Administration"
+- title t '.title'
%p
- %i Hier kannst Du die Gruppen und Benutzerinnen der Foodsoft verwalten.
-.left_column{:style => "width:48%"}
- .box_title
- %h2 Neuste Benutzerinnen
- .column_content
- %table
- %tr
- %th Benutzername
- %th Name
- %th Erstellt am
- - for user in @users
- %tr{:class => cycle('even','odd', :name => 'users')}
- %td= link_to user.nick, [:admin, user]
- %td=h user.name
- %td= format_date(user.created_on)
- %br/
- = link_to 'Alle Benutzerinnen', admin_users_path
- |
- = link_to "Neue Benutzerin", new_admin_user_path
-
-.right_column{:style => "width:48%"}
- .box_title
- %h2 Neuste Gruppen
- .column_content
- %table
- %tr
- %th Gruppenname
- %th Typ
- %th Mitglieder
- - for group in @groups
- %tr{:class => cycle('even','odd', :name => 'groups')}
- %td= link_to group.name, [:admin, group]
- %td= group.class.human_name
- %td= group.users.size
- %br/
- = link_to 'Alle Bestellgruppen', admin_ordergroups_path
- |
- = link_to "Neue Bestellgruppe", new_admin_ordergroup_path
- |
- = link_to 'Alle Arbeitsgruppen', admin_workgroups_path
- |
- = link_to "Neue Arbeitsgruppe", new_admin_workgroup_path
+ %i= t '.first_paragraph'
+.row-fluid
+ .span6
+ %section
+ %h2= t '.newest_users'
+ %table.table.table-striped
+ %thead
+ %tr
+ %th= t '.username'
+ %th= t '.name'
+ %th= t '.created_at'
+ - for user in @users
+ %tr{:class => cycle('even','odd', :name => 'users')}
+ %td= link_to user.nick, [:admin, user]
+ %td=h user.name
+ %td= format_date(user.created_on)
+ = link_to t('.all_users'), admin_users_path
+ |
+ = link_to t('.new_user'), new_admin_user_path, class: 'btn btn-primary btn-small'
+ .span6
+ %section
+ %h2= t '.newest_groups'
+ %table.table.table-striped
+ %thead
+ %tr
+ %th= t '.groupname'
+ %th= t '.type'
+ %th= t '.members'
+ - for group in @groups
+ %tr{:class => cycle('even','odd', :name => 'groups')}
+ %td= link_to group.name, [:admin, group]
+ %td= group.class.model_name.human
+ %td= group.users.size
+ = link_to t('.all_ordergroups'), admin_ordergroups_path
+ |
+ = link_to t('.new_ordergroup'), new_admin_ordergroup_path, class: 'btn btn-primary btn-small'
+ |
+ = link_to t('.all_workgroups'), admin_workgroups_path
+ |
+ = link_to t('.new_workgroup'), new_admin_workgroup_path, class: 'btn btn-primary btn-small'
diff --git a/app/views/admin/ordergroups/_form.html.haml b/app/views/admin/ordergroups/_form.html.haml
index f39a1e4d..23cb846b 100644
--- a/app/views/admin/ordergroups/_form.html.haml
+++ b/app/views/admin/ordergroups/_form.html.haml
@@ -1,20 +1,11 @@
-- form_for [:admin, @ordergroup] do |@form|
- - render :layout => 'shared/group_form' do
- %div{:style => "float:right;width:40%"}
- %p
- = @form.label :contact_person
- %br/
- = @form.text_field :contact_person, :size => 20
- %p
- = @form.label :contact_phone
- %br/
- = @form.text_field :contact_phone, :size => 20
- %p
- = @form.label :contact_address
- %br/
- = @form.text_field :contact_address
-
- %br{ :style => "clear:both" }
- = submit_tag "Speichern"
- |
- = link_to "Abbrechen", admin_ordergroups_path
\ No newline at end of file
+- unless @ordergroup.new_record?
+ %p= t('.first_paragraph', url: link_to(t('.here'), new_invite_path(id: @ordergroup.id), remote: true)).html_safe
+= simple_form_for [:admin, @ordergroup] do |f|
+ = render :layout => 'shared/group_form_fields', :locals => {:f => f} do
+ = f.input :contact_person
+ = f.input :contact_phone
+ = f.input :contact_address
+ = f.input :ignore_apple_restriction
+ .form-actions
+ = f.button :submit
+ = link_to t('ui.or_cancel'), :back
diff --git a/app/views/admin/ordergroups/_ordergroups.html.haml b/app/views/admin/ordergroups/_ordergroups.html.haml
index d12042d3..54618b6f 100644
--- a/app/views/admin/ordergroups/_ordergroups.html.haml
+++ b/app/views/admin/ordergroups/_ordergroups.html.haml
@@ -1,19 +1,14 @@
-%p
- %table{:style => "width:100%"}
- %tr
- %td
- = pagination_links_remote @ordergroups, { :update => "ordergroups" }
- %td{:style => "text-align:right"}
- - if @total > 20
- = items_per_page :update => "ordergroups"
-%table.list
+- if Ordergroup.count > 20
+ = items_per_page
+= pagination_links_remote @ordergroups
+%table.table.table-striped
%thead
%tr
- %th Name
- %th Kontakt
- %th Adresse
- %th Mitglieder
- %th
+ %th= t '.name'
+ %th= t '.contact'
+ %th= t '.address'
+ %th= t '.members'
+ %th= t 'admin.actions'
%tbody
- for ordergroup in @ordergroups
%tr{:class => cycle('even','odd', :name => 'groups')}
@@ -22,7 +17,6 @@
%td= link_to_gmaps ordergroup.contact_address
%td= ordergroup.users.size
%td
- = link_to image_tag('b_users.png', :size => '16x16', :border => "0", :alt => 'Mitlglieder bearbeiten'), memberships_admin_ordergroup_path(ordergroup)
- = link_to(image_tag('b_edit.png', :size => "16x16", :border => "0", :alt => 'Gruppe bearbeiten'), edit_admin_ordergroup_path(ordergroup))
- = link_to(image_tag('b_drop.png', :size => "16x16", :border => "0", :alt => 'Gruppe löschen'), [:admin, ordergroup], |
- :confirm => 'Willst du ' + ordergroup.name + ' wirklich löschen?', :method => :delete) |
\ No newline at end of file
+ = link_to t('ui.edit'), edit_admin_ordergroup_path(ordergroup), class: 'btn btn-mini'
+ = link_to t('ui.delete'), [:admin, ordergroup], :confirm => t('admin.confirm', name: ordergroup.name),
+ :method => :delete, class: 'btn btn-mini btn-danger'
diff --git a/app/views/admin/ordergroups/edit.html.haml b/app/views/admin/ordergroups/edit.html.haml
index a0d5558e..438cf78d 100644
--- a/app/views/admin/ordergroups/edit.html.haml
+++ b/app/views/admin/ordergroups/edit.html.haml
@@ -1,4 +1,3 @@
-- title "Bestellgruppe bearbeiten"
+- title t '.title'
-.edit_form{:style => "width:50em"}
- = render :partial => 'form'
\ No newline at end of file
+= render 'form'
\ No newline at end of file
diff --git a/app/views/admin/ordergroups/index.html.haml b/app/views/admin/ordergroups/index.html.haml
index e449e26e..f3c2133d 100644
--- a/app/views/admin/ordergroups/index.html.haml
+++ b/app/views/admin/ordergroups/index.html.haml
@@ -1,34 +1,15 @@
-- title "Bestellgruppen"
+- title t('.title')
-%p
- %i
- Hier kannst du
- = link_to 'neue Bestellgruppen', new_admin_ordergroup_path
- anlegen, Gruppen bearbeiten und löschen.
-
-%p
- Beachte dabei den Unterschied zwischen Gruppe und Bestellgruppe :
- Eine Bestellgruppe hat ein Konto und kann Essen bestellen. In einer
- %em= link_to 'Arbeisgruppe', admin_workgroups_path
- (z.b. 'Soritiergruppe')
- koordinieren sich die Mitglieder mittels Aufgaben und Nachrichten.
- Nutzer_innen können immer nur einer Bestellgruppe, aber beliebig vielen anderen Gruppen angehören.
-.left_column{:style => "width:100%"}
- .box_title
- %h2 Gruppenübersicht
- .column_content
- #group_filter
- %form{:name=>"sform", :action=>"", :style=>"display:inline;"}
- %label{:for => 'ordergroup_name'} Suche in Name :
- = text_field_tag("query", params['query'], :size => 10 )
-
- = observe_field 'query', :frequency => 2, |
- :before => "Element.show('loader')", |
- :success => "Element.hide('loader')", |
- :update => "ordergroups", |
- :url => admin_ordergroups_path, |
- :with => 'query', |
- :method => :get |
- #ordergroups
- = render :partial => "ordergroups"
- = link_to 'Neue Arbeits', new_admin_ordergroup_path
\ No newline at end of file
+- content_for :actionbar do
+ = link_to t('.new_ordergroup'), new_admin_ordergroup_path, class: 'btn btn-primary'
+
+- content_for :sidebar do
+ %p= t('.first_paragraph', url: link_to(t('.new_ordergroups'), new_admin_ordergroup_path)).html_safe
+ %p= t('.second_paragraph', url: link_to(t('.workgroup'), admin_workgroups_path)).html_safe
+.well.well-small
+ = form_tag admin_ordergroups_path, :method => :get, :remote => true,
+ 'data-submit-onchange' => true, class: 'form-search' do
+ = text_field_tag :query, params[:query], class: 'input-medium search-query',
+ placeholder: t('admin.search_placeholder')
+#ordergroups
+ = render "ordergroups"
\ No newline at end of file
diff --git a/app/views/admin/ordergroups/index.js.haml b/app/views/admin/ordergroups/index.js.haml
new file mode 100644
index 00000000..e991afec
--- /dev/null
+++ b/app/views/admin/ordergroups/index.js.haml
@@ -0,0 +1 @@
+$('#ordergroups').html('#{escape_javascript(render("ordergroups"))}');
diff --git a/app/views/admin/ordergroups/memberships.html.haml b/app/views/admin/ordergroups/memberships.html.haml
deleted file mode 100644
index 8623cbfd..00000000
--- a/app/views/admin/ordergroups/memberships.html.haml
+++ /dev/null
@@ -1,3 +0,0 @@
-= render :partial => 'shared/memberships/members'
-%p{ :style => "clear:both" }
- = link_to 'Gruppenübersicht', admin_ordergroups_path
\ No newline at end of file
diff --git a/app/views/admin/ordergroups/new.html.haml b/app/views/admin/ordergroups/new.html.haml
index b5a6f808..438cf78d 100644
--- a/app/views/admin/ordergroups/new.html.haml
+++ b/app/views/admin/ordergroups/new.html.haml
@@ -1,4 +1,3 @@
-- title "Bestellgruppe anlegen"
+- title t '.title'
-.edit_form{:style => "width:50em"}
- = render :partial => 'form'
\ No newline at end of file
+= render 'form'
\ No newline at end of file
diff --git a/app/views/admin/ordergroups/show.html.haml b/app/views/admin/ordergroups/show.html.haml
index c32958d3..fa1641ca 100644
--- a/app/views/admin/ordergroups/show.html.haml
+++ b/app/views/admin/ordergroups/show.html.haml
@@ -1,15 +1,6 @@
-- title "Bestellgruppe #{@ordergroup.name}"
-.left_column{:style => "width:45em"}
- .box_title
- %h2 Übersicht
- .column_content
- = render :partial => 'shared/group', :locals => { :group => @ordergroup }
- %p
- = link_to 'Gruppe bearbeiten', edit_admin_ordergroup_path(@ordergroup)
- |
- = link_to 'Löschen', [:admin, @ordergroup], :confirm => 'Bist Du sicher?', :method => :delete
- |
- = link_to 'Nachricht senden', :controller => 'messages', :action => 'group', :id => @ordergroup
- |
- = link_to 'Mitglieder bearbeiten', memberships_admin_ordergroup_path(@ordergroup)
-%p{:style => "clear:both"}= link_to "Gruppenübersicht", admin_ordergroups_path
\ No newline at end of file
+- title t '.title', name: @ordergroup.name
+
+%section= render 'shared/group', group: @ordergroup
+= link_to t('ui.edit'), edit_admin_ordergroup_path(@ordergroup), class: 'btn'
+= link_to t('ui.delete'), [:admin, @ordergroup], :confirm => t('.confirm'), :method => :delete, class: 'btn btn-danger'
+= link_to t('.send_message'), new_message_path(:message => {:group_id => @ordergroup.id}), class: 'btn'
diff --git a/app/views/admin/users/_form.html.haml b/app/views/admin/users/_form.html.haml
new file mode 100644
index 00000000..eeb70abf
--- /dev/null
+++ b/app/views/admin/users/_form.html.haml
@@ -0,0 +1,5 @@
+= simple_form_for([:admin, @user]) do |f|
+ = render 'shared/user_form_fields', f: f
+ .form-actions
+ = f.submit
+ = link_to t('ui.or_cancel'), :back
diff --git a/app/views/admin/users/_users.html.haml b/app/views/admin/users/_users.html.haml
index de7e371e..3f8b1df6 100644
--- a/app/views/admin/users/_users.html.haml
+++ b/app/views/admin/users/_users.html.haml
@@ -1,31 +1,23 @@
-%p
- %table{:style => "width:100%"}
- %tr
- %td
- = pagination_links_remote @users
- %td{:style => "text-align:right"}
- - if @total > 20
- = items_per_page
-%table.list
+- if User.count > 20
+ = items_per_page
+= pagination_links_remote @users
+%table.table.table-striped
%thead
%tr
- %th Login
- %th Name
- %th Email
- %th Zugriff auf
- %th Letzter login
- %th{:style => "width:3em"}
+ %th= t '.login'
+ %th= t '.name'
+ %th= t '.email'
+ %th= t 'admin.access_to'
+ %th= t '.last_login'
+ %th(colspan="2")= t 'admin.actions'
%tbody
- for user in @users
-
- %tr{:class => cycle('even','odd', :name => 'users')}
+ %tr
%td= link_to user.nick, [:admin, user]
- %td=h user.name
- %td=h user.email
- %td=h format_roles(user)
- %td=h format_time(user.last_login)
- %td
- = link_to(image_tag('b_edit.png', :size => "16x16", :border => "0", :alt => 'Benutzer_in bearbeiten', :title => 'Benutzer_in bearbeiten'), edit_admin_user_path(user))
- = link_to(image_tag('b_drop.png', :size => "16x16", :border => "0", :alt => 'Benutzer_in löschen', :title => 'Benutzer_in löschen'), |
- [:admin, user], |
- :confirm => 'Willst du ' + user.name + ' wirklich löschen?', :method => :delete) |
+ %td= user.name
+ %td= user.email
+ %td= format_roles(user)
+ %td= format_time(user.last_login)
+ %td= link_to t('ui.edit'), edit_admin_user_path(user), class: 'btn btn-mini'
+ %td= link_to t('ui.delete'), [:admin, user], :confirm => t('admin.confirm', name: user.name),
+ :method => :delete, class: 'btn btn-danger btn-mini'
diff --git a/app/views/admin/users/edit.html.erb b/app/views/admin/users/edit.html.erb
deleted file mode 100644
index 44c5b0e7..00000000
--- a/app/views/admin/users/edit.html.erb
+++ /dev/null
@@ -1,12 +0,0 @@
-Benutzerin bearbeiten
-
-
Benutzerin bearbeiten
-
- <% form_for([:admin, @user]) do |@form| %>
- <%= render :partial => 'shared/user_form' %>
-
-
- <%= submit_tag 'Speichern' %> | <%= link_to 'Abbrechen', admin_users_path %>
- <% end %>
-
-
\ No newline at end of file
diff --git a/app/views/admin/users/edit.html.haml b/app/views/admin/users/edit.html.haml
new file mode 100644
index 00000000..7724f1b7
--- /dev/null
+++ b/app/views/admin/users/edit.html.haml
@@ -0,0 +1,3 @@
+- title t '.title'
+
+= render 'form'
diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml
index 063130b5..d9a6805e 100644
--- a/app/views/admin/users/index.html.haml
+++ b/app/views/admin/users/index.html.haml
@@ -1,28 +1,16 @@
-%h1 Admin/Benutzerinnen
-%p
- %i
- Hier kannst du Benutzer_innen
- = link_to 'neu Anlegen', new_admin_user_path
- , bearbeiten und natürlich auch löschen.
-#newUser{:style => "display:none;"}
- .box_title
- %h2 Neue Benutzerinn
- .column_content#userForm
-.left_column{:style => "width:100%"}
- .box_title
- %h2 Benutzerinnenübersicht
- .column_content
- #user_filter
- %form{:name=>"sform", :action=>"", :style=>"display:inline;"}
- %label{:for => 'article_name'} Suche in Name :
- = text_field_tag("query", params['query'], :size => 10 )
-
- = observe_field 'query', :frequency => 2, |
- :before => "Element.show('loader')", |
- :success => "Element.hide('loader')", |
- :url => admin_users_path, |
- :with => 'query', |
- :method => :get |
- #table
- = render :partial => "users"
- %p= link_to 'Neue Benutzerin', new_admin_user_path
\ No newline at end of file
+- title t '.title'
+
+- content_for :actionbar do
+ = link_to t('.new_user'), new_admin_user_path, class: 'btn btn-primary'
+
+- content_for :sidebar do
+ %p= t('.first_paragraph', url: link_to(t('.new_users'), new_admin_user_path)).html_safe
+
+.well.well-small
+ = form_tag admin_users_path, :method => :get, :remote => true,
+ 'data-submit-onchange' => true, class: 'form-search' do
+ = text_field_tag :user_name, params[:user_name], class: 'input-medium search-query',
+ placeholder: t('admin.search_placeholder')
+
+#users
+ = render "users"
\ No newline at end of file
diff --git a/app/views/admin/users/index.js.haml b/app/views/admin/users/index.js.haml
new file mode 100644
index 00000000..0bf47722
--- /dev/null
+++ b/app/views/admin/users/index.js.haml
@@ -0,0 +1 @@
+$('#users').html('#{escape_javascript(render("users"))}');
diff --git a/app/views/admin/users/new.html.haml b/app/views/admin/users/new.html.haml
index 46b23792..438cf78d 100644
--- a/app/views/admin/users/new.html.haml
+++ b/app/views/admin/users/new.html.haml
@@ -1,13 +1,3 @@
-- title "Neue Benutzerin"
+- title t '.title'
-#newUser
- .box_title
- %h2 Neue Benutzerin
- .column_content#userForm
- - form_for([:admin, @user]) do |@form|
- = render :partial => 'shared/user_form'
- %p{:style => "clear:both" }
- = submit_tag "Speichern"
- |
- = link_to('Abbrechen', admin_users_path )
-%p= link_to 'Benutzerinnenübersicht', admin_users_path
\ No newline at end of file
+= render 'form'
\ No newline at end of file
diff --git a/app/views/admin/users/show.html.erb b/app/views/admin/users/show.html.erb
deleted file mode 100644
index 447b0cca..00000000
--- a/app/views/admin/users/show.html.erb
+++ /dev/null
@@ -1,52 +0,0 @@
-<%=h @user.nick %>
-
-
-
Übersicht
-
-
-
- Mitglied seit <%= distance_of_time_in_words(Time.now, @user.created_on) -%>
-
-
-
Person
-
Nick: <%=h @user.nick %>
-
Name: <%=h @user.name %>
-
Email: <%=h @user.email %>
-
Telefon: <%=h @user.phone %>
-
-
-
- Einstellungen
-
-
-
- <% for setting in User::setting_keys.keys -%>
-
- <%= User::setting_keys[setting] %>
- <%= @user.settings[setting] == '1' ? 'ja' : 'nein' %>
-
- <% end -%>
-
-
-
- Benutzer_in hat Zugriff auf:
-
-
- <%=h format_roles(@user) %>
-
-
-
- <%= link_to 'Bearbeiten', edit_admin_user_path(@user) %>
- | <%= link_to 'Löschen', [:admin, @user], :confirm => "Willst du #{@user.first_name} wirklich rausschmeißen?", :method => :delete %>
- | <%= link_to "Nachricht senden", user_message_path(@user.id) %>
-
-
-
Gruppenabos
-
- <% for membership in Membership.find_all_by_user_id(@user.id) -%>
-
- <%= link_to(membership.group.name, [:admin, membership.group]) %>
-
- <% end -%>
-
-
diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml
new file mode 100644
index 00000000..a954b7d5
--- /dev/null
+++ b/app/views/admin/users/show.html.haml
@@ -0,0 +1,39 @@
+- title @user.nick
+
+.row-fluid
+ .span3
+ .well
+ %h4= t '.person'
+ %p= t '.member_since', time: distance_of_time_in_words(Time.now, @user.created_on)
+ %dl
+ %dt= t '.nick'
+ %dd= @user.nick
+ %dt= t '.name'
+ %dd= h @user.name
+ %dt= t '.email'
+ %dd= @user.email
+ %dt= t '.phone'
+ %dd= @user.phone
+ %dt= t 'admin.access_to'
+ %dd= format_roles(@user)
+ .span5
+ .well
+ %h4= t '.preference'
+ %table.table
+ - for setting in User::setting_keys.keys
+ %tr
+ %td= User::setting_keys[setting]
+ %td= @user.settings[setting] == '1' ? t('simple_form.yes') : t('simple_form.no')
+ .span3
+ .well
+ %h4= t '.groupabos'
+ %ul.unstyled
+ - for membership in Membership.find_all_by_user_id(@user.id)
+ %li= link_to(membership.group.name, [:admin, membership.group])
+
+%hr/
+%p
+ = link_to t('ui.edit'), edit_admin_user_path(@user), class: 'btn'
+ = link_to t('ui.delete'), [:admin, @user], :confirm => t('.confirm', user: @user.first_name),
+ :method => :delete, class: 'btn btn-danger'
+ = link_to t('.send_message'), new_message_path(:message => {:mail_to => @user.id}), class: 'btn'
diff --git a/app/views/admin/workgroups/_form.html.haml b/app/views/admin/workgroups/_form.html.haml
index 0e394569..a05ef459 100644
--- a/app/views/admin/workgroups/_form.html.haml
+++ b/app/views/admin/workgroups/_form.html.haml
@@ -1,30 +1,12 @@
-- form_for [:admin, @workgroup] do |@form|
- - render :layout => 'shared/group_form' do
- %div{:style => "float:right;width:40%"}
- %h3 Gruppe hat Zugriff auf
- %table
- %tr
- %td
- = @form.label :role_admin, "Administration"
- %td= @form.check_box :role_admin
- %tr
- %td
- = @form.label :role_finance, "Finanzen"
- %td= @form.check_box :role_finance
- %tr
- %td
- = @form.label :role_suppliers, "Lieferantenverwaltung"
- %td= @form.check_box :role_suppliers
- %tr
- %td
- = @form.label :role_article_meta, "Artikelverwaltung"
- %td= @form.check_box :role_article_meta
- %tr
- %td
- = @form.label :role_orders, "Bestellungsverwaltung"
- %td= @form.check_box :role_orders
-
- %br{ :style => "clear:both" }
- = submit_tag "Speichern"
- |
- = link_to "Abbrechen", admin_workgroups_path
\ No newline at end of file
+%p= t('.first_paragraph', url: link_to(t('.here'), new_invite_path(id: @workgroup.id), remote: true)).html_safe
+= simple_form_for [:admin, @workgroup] do |f|
+ = render :layout => 'shared/group_form_fields', :locals => {:f => f} do
+ %h4= t 'admin.access_to'
+ = f.input :role_admin
+ = f.input :role_finance
+ = f.input :role_suppliers
+ = f.input :role_article_meta
+ = f.input :role_orders
+ .form-actions
+ = f.button :submit
+ = link_to t('ui.or_cancel'), :back
diff --git a/app/views/admin/workgroups/_workgroups.html.haml b/app/views/admin/workgroups/_workgroups.html.haml
index 1b279d59..c7250e83 100644
--- a/app/views/admin/workgroups/_workgroups.html.haml
+++ b/app/views/admin/workgroups/_workgroups.html.haml
@@ -1,26 +1,20 @@
-%p
- %table{:style => "width:100%"}
- %tr
- %td
- = pagination_links_remote @workgroups, { :update => "workgroups" }
- %td{:style => "text-align:right"}
- - if @total.size > 20
- = items_per_page :update => "workgroups"
-%table.list
+- if Workgroup.count > 20
+ = items_per_page
+= pagination_links_remote @workgroups
+%table.table.table-striped
%thead
%tr
- %th Name
- %th Mitglieder
- %th Zugriff auf
- %th
+ %th= t '.name'
+ %th= t '.members'
+ %th= t 'admin.access_to'
+ %th= t 'admin.actions'
%tbody
- for workgroup in @workgroups
- %tr{:class => cycle('even','odd', :name => 'groups')}
+ %tr
%td= link_to workgroup.name, [:admin, workgroup]
%td= workgroup.users.size
%td= format_roles(workgroup)
%td
- = link_to image_tag('b_users.png', :size => '16x16', :border => "0", :alt => 'Mitlglieder bearbeiten'), memberships_admin_workgroup_path(workgroup)
- = link_to(image_tag('b_edit.png', :size => "16x16", :border => "0", :alt => 'Gruppe bearbeiten'), edit_admin_workgroup_path(workgroup))
- = link_to(image_tag('b_drop.png', :size => "16x16", :border => "0", :alt => 'Gruppe löschen'), [:admin, workgroup], |
- :confirm => 'Willst du ' + workgroup.name + ' wirklich löschen?', :method => :delete) |
+ = link_to t('ui.edit'), edit_admin_workgroup_path(workgroup), class: 'btn btn-mini'
+ = link_to t('ui.delete'), [:admin, workgroup], :confirm => t('admin.confirm', name: workgroup.name),
+ :method => :delete, class: 'btn btn-mini btn-danger'
diff --git a/app/views/admin/workgroups/edit.html.haml b/app/views/admin/workgroups/edit.html.haml
index 833c72c1..438cf78d 100644
--- a/app/views/admin/workgroups/edit.html.haml
+++ b/app/views/admin/workgroups/edit.html.haml
@@ -1,4 +1,3 @@
-- title "Arbeitsgruppe bearbeiten"
+- title t '.title'
-.edit_form{:style => "width:50em"}
- = render :partial => 'form'
\ No newline at end of file
+= render 'form'
\ No newline at end of file
diff --git a/app/views/admin/workgroups/index.html.haml b/app/views/admin/workgroups/index.html.haml
index 4fe1d34c..80a27d6c 100644
--- a/app/views/admin/workgroups/index.html.haml
+++ b/app/views/admin/workgroups/index.html.haml
@@ -1,34 +1,15 @@
-- title "List workgroups"
+- title t '.title'
-%p
- %i
- Hier kannst du
- = link_to 'neue Arbeitsgruppen', new_admin_workgroup_path
- anlegen, Gruppen bearbeiten und löschen.
-
-%p
- Beachte dabei den Unterschied zwischen Gruppe und Bestellgruppe :
- Eine
- %em= link_to 'Bestellgruppe', '/admin/ordergroups'
- hat ein Konto und kann Essen bestellen. In einer Arbeitsgruppe (z.b. 'Soritiergruppe')
- koordinieren sich die Mitglieder mittels Aufgaben und Nachrichten.
- Nutzer_innen können immer nur einer Bestellgruppe, aber beliebig vielen anderen Gruppen angehören.
-.left_column{:style => "width:100%"}
- .box_title
- %h2 Gruppenübersicht
- .column_content
- #group_filter
- %form{:name=>"sform", :action=>"", :style=>"display:inline;"}
- %label{:for => 'workgroup_name'} Suche in Name :
- = text_field_tag("query", params['query'], :size => 10 )
-
- = observe_field 'query', :frequency => 2, |
- :before => "Element.show('loader')", |
- :success => "Element.hide('loader')", |
- :update => "workgroups", |
- :url => admin_workgroups_path, |
- :with => 'query', |
- :method => :get |
- #workgroups
- = render :partial => "workgroups"
- = link_to 'Neue Arbeits', new_admin_workgroup_path
\ No newline at end of file
+- content_for :actionbar do
+ = link_to t('.new_workgroup'), new_admin_workgroup_path, class: 'btn btn-primary'
+
+- content_for :sidebar do
+ %p= t('.first_paragraph', url: link_to(t('.new_workgroups'), new_admin_workgroup_path)).html_safe
+ %p= t('.second_paragraph', url: link_to(t('.ordergroup'), admin_ordergroups_path)).html_safe
+.well.well-small
+ = form_tag admin_workgroups_path, :method => :get, :remote => true,
+ 'data-submit-onchange' => true, class: 'form-search' do
+ = text_field_tag :query, params[:query], class: 'input-medium search-query',
+ placeholder: t('admin.search_placeholder')
+#workgroups
+ = render "workgroups"
\ No newline at end of file
diff --git a/app/views/admin/workgroups/index.js.haml b/app/views/admin/workgroups/index.js.haml
new file mode 100644
index 00000000..e21e8b7d
--- /dev/null
+++ b/app/views/admin/workgroups/index.js.haml
@@ -0,0 +1 @@
+$('#workgroups').html('#{escape_javascript(render("workgroups"))}');
diff --git a/app/views/admin/workgroups/memberships.html.haml b/app/views/admin/workgroups/memberships.html.haml
deleted file mode 100644
index 122ab580..00000000
--- a/app/views/admin/workgroups/memberships.html.haml
+++ /dev/null
@@ -1,3 +0,0 @@
-= render :partial => 'shared/memberships/members'
-%p{ :style => "clear:both" }
- = link_to 'Gruppenübersicht', admin_workgroups_path
\ No newline at end of file
diff --git a/app/views/admin/workgroups/new.html.haml b/app/views/admin/workgroups/new.html.haml
index d9236cd2..438cf78d 100644
--- a/app/views/admin/workgroups/new.html.haml
+++ b/app/views/admin/workgroups/new.html.haml
@@ -1,4 +1,3 @@
-- title "Erstelle Arbeitsgruppe"
+- title t '.title'
-.edit_form{:style => "width:50em"}
- = render :partial => 'form'
\ No newline at end of file
+= render 'form'
\ No newline at end of file
diff --git a/app/views/admin/workgroups/show.html.haml b/app/views/admin/workgroups/show.html.haml
index 62b7985c..6f609001 100644
--- a/app/views/admin/workgroups/show.html.haml
+++ b/app/views/admin/workgroups/show.html.haml
@@ -1,16 +1,6 @@
-- title "Arbeitsgruppe #{@workgroup.name}"
-.left_column{:style => "width:45em"}
- .box_title
- %h2 Übersicht
- .column_content
- = render :partial => 'shared/group', :locals => { :group => @workgroup }
+- title t '.title', name: @workgroup.name
- %p
- = link_to 'Gruppe bearbeiten', edit_admin_workgroup_path(@workgroup)
- |
- = link_to 'Löschen', [:admin, @workgroup], :confirm => 'Bist Du sicher?', :method => :delete
- |
- = link_to 'Nachricht senden', :controller => 'messages', :action => 'group', :id => @workgroup
- |
- = link_to 'Mitglieder bearbeiten', memberships_admin_workgroup_path(@workgroup)
-%p{:style => "clear:both"}= link_to "Gruppenübersicht", admin_workgroups_path
\ No newline at end of file
+%section= render 'shared/group', group: @workgroup
+= link_to t('ui.edit'), edit_admin_workgroup_path(@workgroup), class: 'btn'
+= link_to t('ui.delete'), [:admin, @workgroup], :confirm => t('.confirm'), :method => :delete, class: 'btn btn-danger'
+= link_to_new_message(message_params: {group_id: @workgroup.id})
diff --git a/app/views/article_categories/_form.html.haml b/app/views/article_categories/_form.html.haml
new file mode 100644
index 00000000..5e062ba1
--- /dev/null
+++ b/app/views/article_categories/_form.html.haml
@@ -0,0 +1,6 @@
+= simple_form_for @article_category do |f|
+ = f.input :name
+ = f.input :description
+ .form-actions
+ = f.submit class: 'btn'
+ = link_to t('ui.or_cancel'), article_categories_path
diff --git a/app/views/article_categories/_form.rhtml b/app/views/article_categories/_form.rhtml
deleted file mode 100644
index 357b7252..00000000
--- a/app/views/article_categories/_form.rhtml
+++ /dev/null
@@ -1,24 +0,0 @@
-<% remote_form_for @article_category,
- :before => "Element.show('loader')",
- :success => "Element.hide('loader')" do |@f| %>
-
- <%= @f.error_messages %>
-
-
- Name
- Beschreibung
-
-
-
- <%= @f.text_field :name, :size => 20 %>
-
-
- <%= @f.text_field :description, :size => 30 %>
-
-
-
-
-
- <%= submit_tag "Speichern" %> | <%= link_to_function("Abbrechen", "Element.hide('category_form')") %>
-<% end %>
-
diff --git a/app/views/article_categories/_list.rhtml b/app/views/article_categories/_list.rhtml
deleted file mode 100644
index baa2c7ae..00000000
--- a/app/views/article_categories/_list.rhtml
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
- Name
- Beschreibung
-
-
-<% for article_category in ArticleCategory.find(:all) -%>
- 'category') -%>" id="category_<%= article_category.id -%>">
- <%=h article_category.name -%>
- <%=h article_category.description -%>
- <%= link_to_remote icon(:edit),
- :url => edit_article_category_path(article_category),
- :method => :get,
- :before => "Element.show('loader')",
- :success => "Element.hide('loader')" -%>
- <%= link_to_remote icon(:delete),
- :url => article_category,
- :method => :delete,
- :confirm => 'Are you sure?' -%>
-
-<% end -%>
-
-
-<%= link_to_remote 'Neue Kategorie', :url => new_article_category_path,
- :method => :get,
- :before => "Element.show('loader')",
- :success => "Element.hide('loader')" %>
diff --git a/app/views/article_categories/edit.html.haml b/app/views/article_categories/edit.html.haml
new file mode 100644
index 00000000..624324db
--- /dev/null
+++ b/app/views/article_categories/edit.html.haml
@@ -0,0 +1,3 @@
+- title t('.title')
+
+= render 'form'
diff --git a/app/views/article_categories/index.html.haml b/app/views/article_categories/index.html.haml
index 137dfdc5..dc18f042 100644
--- a/app/views/article_categories/index.html.haml
+++ b/app/views/article_categories/index.html.haml
@@ -1,8 +1,19 @@
-- title "Artikelkategorien"
+- title t('.title')
-.left_column{:style => "width:50em"}
- .box_title
- %h2 Artikelkategorien
- .column_content#categories
- #category_form.box.edit_form{:style => "display:none;margin-bottom:1em;"}
- #category_list= render :partial => 'article_categories/list'
\ No newline at end of file
+%p= link_to t('.new'), new_article_category_path, class: 'btn btn-primary'
+
+%table.table.table-striped
+ %thead
+ %tr
+ %th= t('simple_form.labels.article_category.name')
+ %th= t('simple_form.labels.article_category.description')
+ %th
+ %tbody
+ - @article_categories.each do |article_category|
+ %tr
+ %td= article_category.name
+ %td= article_category.description
+ %td
+ = link_to t('ui.edit'), edit_article_category_path(article_category), class: 'btn btn-mini'
+ = link_to t('ui.delete'), article_category, :method => :delete, :confirm => t('.confirm_delete'),
+ class: 'btn btn-mini btn-danger'
diff --git a/app/views/article_categories/new.html.haml b/app/views/article_categories/new.html.haml
new file mode 100644
index 00000000..624324db
--- /dev/null
+++ b/app/views/article_categories/new.html.haml
@@ -0,0 +1,3 @@
+- title t('.title')
+
+= render 'form'
diff --git a/app/views/articles/_article.html.haml b/app/views/articles/_article.html.haml
new file mode 100644
index 00000000..aaa6210c
--- /dev/null
+++ b/app/views/articles/_article.html.haml
@@ -0,0 +1,17 @@
+%tr{class: row_classes(article)}[article]
+ %td= check_box_tag 'selected_articles[]', article.id.to_s, false, {:id => "checkbox_#{article.id}", 'data-ignore-onchange' => true}
+ %td{'data-check-this' => "#checkbox_#{article.id}", :class => 'click-me'}= article.name
+ %td= article.origin
+ %td= truncate(article.article_category.name, :length => 11) if article.article_category
+ %td= article.unit
+ %td= truncate(article.note, :length => 11)
+ %td= article.unit_quantity
+ %td{:class => "currency"}
+ %acronym{:title => t('.last_update', last_update: format_date(article.updated_at), gross_price: number_to_currency(article.gross_price))}
+ = number_to_currency(article.price)
+ %td= number_to_percentage(article.tax) if article.tax != 0
+ %td= number_to_currency(article.deposit) if article.deposit != 0
+ %td= link_to t('ui.edit'), edit_supplier_article_path(@supplier, article),
+ :remote => true, class: 'btn btn-mini'
+ %td= link_to t('ui.delete'), [@supplier, article],
+ :method => :delete, :confirm => t('.confirm_delete'), :remote => true, class: 'btn btn-mini btn-danger'
diff --git a/app/views/articles/_article_row.rhtml b/app/views/articles/_article_row.rhtml
deleted file mode 100644
index 7ad87f48..00000000
--- a/app/views/articles/_article_row.rhtml
+++ /dev/null
@@ -1,27 +0,0 @@
-
- <%= check_box_tag 'selected_articles[]', @article.id.to_s, false,
- {:id => "checkbox_#{@article.id.to_s}", :onclick => "checkRow('#{@article.id.to_s}')"} %>
-
-<%=h @article.name -%>
-<%= @article.origin -%>
-<%=h truncate(@article.article_category.name, :length => 11) if @article.article_category -%>
-<%=h @article.unit -%>
-<%=h truncate(@article.note, :length => 11) -%>
-<%= @article.unit_quantity -%>
-
-
- <%= number_to_currency(@article.price) -%>
-
-
-<%= number_to_percentage(@article.tax) if @article.tax != 0 -%>
-<%= number_to_currency(@article.deposit) if @article.deposit != 0 -%>
-
- <%= remote_link_to icon(:edit, :onclick => "checkRow('#{@article.id.to_s}')"),
- :url => edit_supplier_article_path(@supplier, @article) %>
- <%= remote_link_to icon(:delete, :onclick => "checkRow('#{@article.id.to_s}')"),
- :url => [@supplier, @article],
- :method => :delete,
- :confirm => 'Bist du sicher?' %>
-
-
\ No newline at end of file
diff --git a/app/views/articles/_articles.html.haml b/app/views/articles/_articles.html.haml
index 33d7a17f..fd00f23d 100644
--- a/app/views/articles/_articles.html.haml
+++ b/app/views/articles/_articles.html.haml
@@ -1,52 +1,37 @@
-%p
- Gefundene Artikel:
- %b= @total
+- if @supplier.articles.count > 20
+ = items_per_page
+= pagination_links_remote @articles
-%p
- %table{:style => "width:100%"}
- %tr
- %td
- = pagination_links_remote @articles, :params => {:sort => params[:sort]}
- %td{:style => "text-align:right"}
- - if @total > 30
- = items_per_page :per_page_options => [30, 100, 500]
-
-%table#articles_table.list.articles
+%table#articles_table.table.table-hover
%thead
%tr
%th
- %th[sort_td_class_helper "name"]
- = sort_link_helper "Name", "name"
+ %th= sort_link_helper t('simple_form.labels.article.name'), "name"
%th
- %th[sort_td_class_helper "category"]
- = sort_link_helper "Kategorie", "category"
- %th[sort_td_class_helper "unit"]
- = sort_link_helper "Einheit", "unit"
- %th[sort_td_class_helper "note"]
- = sort_link_helper "Notiz", "note"
- %th{:style => "width: 4em;"} Gebgr.
- %th{:style => "width: 4em;"} Preis
- %th{:style => "width: 3.5em;"} MwSt
- %th{:style => "width: 4em;"} Pfand
+ %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{:style => "width: 3em;"}
%tbody#listbody
- - if @total > 0
- - for @article in @articles
- %tr{ :class => cycle('even','odd') + row_classes(@article), :id => @article.id, :onclick => "checkRow('#{@article.id.to_s}')"}
- = render :partial => 'article_row'
+ - unless @articles.empty?
+ - for article in @articles
+ = render(article)
%tfoot
%tr
%td{:colspan => '11'}
- = check_box_tag :checkall, 1, false, :onclick => 'checkUncheckAll(this)'
- %select{:name => "selected_action"}
- %option{:value => '', :selected => 'selected'} Aktion wählen ...
- %option{:value => "destroy", :onclick => "if (confirm('Willst Du wirklich alle gewählten Artikel löschen?')) { this.up('form').submit(); }; return false;"} Artikel löschen
- %option{:value => "setNotAvailable", :onclick => "this.up('form').submit()"} Artikel sind nicht mehr verfügbar
- %option{:value => "setAvailable", :onclick => "this.up('form').submit()"} Artikel sind verfügbar
-
+ = check_box_tag :checkall, 1, false, 'data-check-all' => '#articlesInListForm', 'data-ignore-onchange' => true
+ %select{:name => "selected_action", 'data-submit-onchange' => true}
+ %option{:value => '', :selected => 'selected'}= t '.option_select'
+ %option{:value => "destroy", 'data-confirm' => t('.confirm_delete')}= t '.option_delete'
+ %option{:value => "setNotAvailable"}= t '.option_not_available'
+ %option{:value => "setAvailable"}= t '.option_available'
= hidden_field_tag 'supplier_id', @supplier.id
-%p= pagination_links_remote @articles, :params => {:sort => params[:sort]}
-= hidden_field_tag :per_page, params[:per_page]
\ No newline at end of file
+= pagination_links_remote @articles
diff --git a/app/views/articles/_destroyActiveArticle.haml b/app/views/articles/_destroyActiveArticle.haml
deleted file mode 100644
index c18bde5a..00000000
--- a/app/views/articles/_destroyActiveArticle.haml
+++ /dev/null
@@ -1,9 +0,0 @@
-%tr.edit_inline{:id=> "edit_"+@article.id.to_s}
- %td{:colspan=>"10"}
- =h @article.name
- wird in laufenden Bestellungen verwendet und kann nicht gelöscht werden.
- Bitte zuerst den Artikel aus den Bestellungen
- = link_to "entfernen", :controller => 'orders', :action => 'edit', :id => @order
- oder
- = link_to_function 'abbrechen', "Element.remove('edit_#{@article.id.to_s}')"
-
\ No newline at end of file
diff --git a/app/views/articles/_destroy_active_article.haml b/app/views/articles/_destroy_active_article.haml
new file mode 100644
index 00000000..73c59e1c
--- /dev/null
+++ b/app/views/articles/_destroy_active_article.haml
@@ -0,0 +1,3 @@
+%tr.edit_inline{:id=> "edit_"+@article.id.to_s}
+ %td{:colspan=>"10"}
+ = t('.note', article: h(@article.name), drop_link: link_to(t('.drop'), :controller => 'orders', :action => 'edit', :id => @order)).html_safe
diff --git a/app/views/articles/_edit.haml b/app/views/articles/_edit.haml
deleted file mode 100644
index 10e473dc..00000000
--- a/app/views/articles/_edit.haml
+++ /dev/null
@@ -1,7 +0,0 @@
-%h2
- Bearbeiten von
- = @article.name
-zuletzt aktualisiert am:
-= format_time(@article.updated_at)
-
-= render :partial => "form"
diff --git a/app/views/articles/_edit_all_table.html.haml b/app/views/articles/_edit_all_table.html.haml
new file mode 100644
index 00000000..eeb609c4
--- /dev/null
+++ b/app/views/articles/_edit_all_table.html.haml
@@ -0,0 +1,35 @@
+%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'
+ %tbody
+ - @articles.each_with_index do |article, index|
+ = fields_for "articles[#{article.id || index}]", article do |form|
+ %tr
+ %td= form.check_box 'availability'
+ %td= form.text_field 'name', class: 'input-medium'
+ %td= form.text_field 'unit', class: 'input-mini'
+ %td= form.text_field 'price', class: 'input-mini'
+ %td= form.text_field 'unit_quantity', class: 'input-mini'
+ %td= form.text_field 'order_number', class: 'input-mini'
+ %td= form.text_field 'note', class: 'input-medium'
+ %td= form.collection_select 'article_category_id', ArticleCategory.all,
+ :id, :name, { :include_blank => true }, class: 'input-small'
+ %td= form.text_field 'tax', class: 'input-mini'
+ %td= form.text_field 'deposit', class: 'input-mini'
+ - unless article.errors.empty?
+ %tr.alert
+ %td(colspan="10")= article.errors.full_messages.join(", ")
diff --git a/app/views/articles/_form.html.haml b/app/views/articles/_form.html.haml
index f2430210..485386d1 100644
--- a/app/views/articles/_form.html.haml
+++ b/app/views/articles/_form.html.haml
@@ -1,45 +1,24 @@
-- remote_form_for [@supplier, @article], :before => "Element.show('loader')", |
- :success => "Element.hide('loader')" do |form| |
+= simple_form_for [@supplier, @article], :validate => true, :remote => true do |f|
+ = f.hidden_field :shared_updated_on
+ = f.hidden_field :supplier_id
+ .modal-header
+ = link_to t('ui.marks.close').html_safe, '#', class: 'close', data: {dismiss: 'modal'}
+ %h3= t '.title'
+ .modal-body
+ = f.input :availability
+ = f.input :name
+ = f.input :origin
+ = f.input :manufacturer
+ = f.input :unit
+ = f.input :note
+ = f.association :article_category
- = form.error_messages
- %p
- %b Verfügbar?
- = form.check_box :availability
- %table{ :style => "width: 20em"}
- %tr
- %th Name
- %th Herkunft
- %th Hersteller
- %th Einheit
- %th Notiz
- %th kategorie
- %tbody
- %tr
- %td= form.text_field :name, :size => 15
- %td= form.text_field :origin, :size => 5
- %td= form.text_field :manufacturer, :size => 8
- %td= form.text_field :unit, :size => 5
- %td= form.text_field :note, :size => 15
- %td= form.select :article_category_id, ArticleCategory.find(:all, :order => 'name').collect {|a| [ a.name, a.id ] }
- %br/
- %table{ :style=>"width:35em"}
- %tr
- %th Nettopreis
- %th Gebindegröße
- %th Bestellnummer
- %th MwSt
- %th Pfand
- %tbody
- %tr
- %td= form.text_field :price, :size => 5
- %td= form.text_field :unit_quantity, :size => 5
- %td= form.text_field :order_number, :size => 10
- %td= form.text_field :tax, :size => 5
- %td= form.text_field :deposit, :size => 5
-
- = form.hidden_field :shared_updated_on
- = form.hidden_field :supplier_id
+ = f.input :price
+ = f.input :unit_quantity
+ = f.input :order_number
+ = f.input :tax
+ = f.input :deposit
+ .modal-footer
+ = link_to t('ui.close'), '#', class: 'btn', data: {dismiss: 'modal'}
+ = f.submit class: 'btn btn-primary'
- = submit_tag "Speichern"
- |
- = link_to_function "Abbrechen", "Element.hide('edit_article')"
\ No newline at end of file
diff --git a/app/views/articles/_import_search_results.haml b/app/views/articles/_import_search_results.haml
index 56a58ea5..6d4c6720 100644
--- a/app/views/articles/_import_search_results.haml
+++ b/app/views/articles/_import_search_results.haml
@@ -1,27 +1,32 @@
-%p= pagination_links_remote @articles, :per_page => 10, |
- :params => {:import_query => params[:import_query], :regional => params[:regional]} |
-%table.list
- %thead
- %tr
- %th Name
- %th Herkunft
- %th Hersteller
- %th Notiz
- %th{:style => "width:4em"} Preis
- %th Einheit
- %th GebGröße
- %th
- %tbody
- - for article in @articles
- %tr{:class => cycle('even','odd', :name => 'import_search_results')}
- %td= highlight_phrase article.name, params[:import_query]
- %td= article.origin
- %td= article.manufacturer
- %td= article.note
- %td= number_to_currency(article.price)
- %td= article.unit
- %td= article.unit_quantity
- %td= link_to_remote 'importieren', |
- :url => import_supplier_articles_path(@supplier, :shared_article_id => article.id), |
- :method => :get |
-
\ No newline at end of file
+- if @articles.empty?
+ %p= t '.not_found'
+- else
+ = pagination_links_remote @articles, :params => {:search => search_params}
+ %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
+ %tbody
+ - for article in @articles
+ %tr
+ %td= highlight article.name, params[:search][:name_contains_all]
+ %td= article.origin
+ %td= article.manufacturer
+ %td= article.note
+ %td= number_to_currency(article.price)
+ %td= article.unit
+ %td= article.unit_quantity
+ %td
+ - logger.debug "[debug] #{article.attributes.inspect}"
+ - if @supplier.articles.undeleted.where(order_number: article.number).exists?
+ %i.icon-ok= t '.already_imported'
+ - else
+ = link_to t('.action_import'), import_supplier_articles_path(@supplier, :shared_article_id => article.id),
+ :remote => true, class: 'btn btn-small btn-success'
diff --git a/app/views/articles/_new.haml b/app/views/articles/_new.haml
deleted file mode 100644
index 8b07a58b..00000000
--- a/app/views/articles/_new.haml
+++ /dev/null
@@ -1,2 +0,0 @@
-%h3 Neuer Artikel
-= render :partial => 'form'
\ No newline at end of file
diff --git a/app/views/articles/_new_article_row.haml b/app/views/articles/_new_article_row.haml
deleted file mode 100644
index 5fc86275..00000000
--- a/app/views/articles/_new_article_row.haml
+++ /dev/null
@@ -1,2 +0,0 @@
-%tr{:class => cycle('even','odd'), :id => @article.id, :onclick => "checkRow('#{@article.id.to_s}')"}
- = render :partial => 'article_row'
\ No newline at end of file
diff --git a/app/views/articles/create.js.haml b/app/views/articles/create.js.haml
new file mode 100644
index 00000000..b716d170
--- /dev/null
+++ b/app/views/articles/create.js.haml
@@ -0,0 +1,2 @@
+$('#modalContainer').modal('hide');
+$('#listbody').prepend('#{escape_javascript(render(@article))}');
diff --git a/app/views/articles/destroy.js.haml b/app/views/articles/destroy.js.haml
new file mode 100644
index 00000000..da7c5a62
--- /dev/null
+++ b/app/views/articles/destroy.js.haml
@@ -0,0 +1,4 @@
+- if @order
+ $('#article_#{@article.id}').after('#{escape_javascript(render("destroy_active_article"))}');
+- else
+ $('#article_#{@article.id}').remove();
diff --git a/app/views/articles/edit_all.html.haml b/app/views/articles/edit_all.html.haml
new file mode 100644
index 00000000..ec865295
--- /dev/null
+++ b/app/views/articles/edit_all.html.haml
@@ -0,0 +1,10 @@
+- title t('.title', supplier: @supplier.name)
+%p
+ %i= t '.note'
+= form_tag(update_all_supplier_articles_path(@supplier)) do
+ = render 'edit_all_table'
+ %br/
+ %i= t '.warning'
+ .form-actions
+ = submit_tag t('.submit'), class: 'btn btn-primary'
+ = link_to t('ui.or_cancel'), supplier_articles_path(@supplier)
diff --git a/app/views/articles/edit_all.rhtml b/app/views/articles/edit_all.rhtml
deleted file mode 100644
index 4183db2e..00000000
--- a/app/views/articles/edit_all.rhtml
+++ /dev/null
@@ -1,64 +0,0 @@
-Alle Artikel von <%= @supplier.name %> bearbeiten
-
-
-
- <% form_tag do -%>
- <%= select_tag :switch_supplier,
- options_for_select( Supplier.all.collect {|s| [s.name, url_for(edit_all_supplier_articles_path(s))] },
- url_for(edit_all_supplier_articles_path(@supplier)) ),
- :onchange => "redirectTo(this)",
- :style => "font-size: 0.9em;margin-left:1em;" %>
- <% end %>
-
-
-
-
-
-
<%= link_to 'zurück zur Liste', supplier_articles_path(@supplier) -%>
-
-
- Pflichtfelder sind: Name, Einheit, (netto) Preis und Bestellnummer.
-
-
- <% form_tag(update_all_supplier_articles_path(@supplier)) do %>
-
-
-
- verf.
- Name
- Einheit
- Preis
- GebGr
- Best.Nr.
- Notiz
- Kategorie
- MwSt.
- Pfand
-
-
- <% for article in @articles %>
- <% fields_for 'articles[]', article do |form| %>
- >
-
- <%= form.check_box 'availability' -%>
- <%= form.text_field 'name', :size => 0 -%>
-
- <%= form.text_field 'unit', :size => 5 -%>
- <%= form.text_field 'price', :size => 4 -%>
- <%= form.text_field 'unit_quantity', :size => 4 -%>
- <%= form.text_field 'order_number', :size => 6 -%>
- <%= form.text_field 'note', :size => 15 -%>
- <%= form.select 'article_category_id', ArticleCategory.find(:all).collect {|a| [ a.name, a.id ] }, { :include_blank => true } -%>
- <%= form.text_field 'tax', :size => 4 -%>
- <%= form.text_field 'deposit', :size => 4 -%>
-
- <% end %>
- <% end %>
-
-
-
-
Achtung, alle Artikel werden aktualisiert!
- <%= submit_tag 'Alle Artikel aktualisieren'%> | <%= link_to 'Abbrechen', supplier_articles_path(@supplier) %>
- <% end %>
-
-
\ No newline at end of file
diff --git a/app/views/articles/index.haml b/app/views/articles/index.haml
index 2f7bc5df..f6e11a60 100644
--- a/app/views/articles/index.haml
+++ b/app/views/articles/index.haml
@@ -1,65 +1,49 @@
-- title "Artikel von #{@supplier.name}"
+- title t('.title', supplier: @supplier.name, count: @supplier.articles.undeleted.count)
-// import menu
-- unless @supplier.shared_supplier.nil?
- .menu{:style => 'width: 16em'}
- %ul
- %li
- Zugriff auf externe Datenbank
- %ul
- %li= link_to_function "Suchen/Importieren", "Element.toggle('import')"
- %li= link_to "Synchronisieren", sync_supplier_articles_path(@supplier), :method => :post
+.well.well-small
+ .btn-toolbar
+ = form_tag supplier_articles_path(@supplier), method: :get, remote: true, class: 'form-search pull-right',
+ 'data-submit-onchange' => true do
+ = text_field_tag :query, params[:query], class: 'input-medium search-query',
+ placeholder: t('.search_placeholder')
+ .btn-group
+ = link_to t('.new'), new_supplier_article_path(@supplier), remote: true, class: 'btn btn-primary'
+ = link_to t('.edit_all'), edit_all_supplier_articles_path(@supplier), class: 'btn'
+ = link_to t('.upload'), upload_supplier_articles_path(@supplier), class: 'btn'
+ - if current_user.role_orders?
+ = link_to t('.new_order'), new_order_path(supplier_id: @supplier), class: 'btn'
-#change_supplier{:style => "padding:0 0 0.5em 0.7em;"}
- %span{:style => "float:left"}
- Lieferantin wechseln:
- - form_tag do
- = select_tag :switch_supplier, |
- options_for_select( Supplier.all(:order => 'name').collect {|s| [s.name, url_for(supplier_articles_path(s))] }, |
- url_for(supplier_articles_path(@supplier)) ), |
- :onchange => "redirectTo(this)", |
- :style => "font-size: 0.9em;margin-left:1em;" |
+ - unless @supplier.shared_supplier.nil?
+ .btn-group
+ = link_to '#', data: {toggle: 'dropdown'}, class: 'btn btn-success dropdown-toggle' do
+ = t '.ext_db.title'
+ %span.caret
+ %ul.dropdown-menu
+ %li= link_to t('.ext_db.import'), "#import", 'data-toggle-this' => '#import'
+ %li= link_to t('.ext_db.sync'), sync_supplier_articles_path(@supplier), method: :post
+
+ .btn-group
+ = link_to '#', data: {toggle: 'dropdown'}, class: 'btn dropdown-toggle' do
+ = t '.change_supplier'
+ %span.caret
+ %ul.dropdown-menu
+ - Supplier.undeleted.where('id != ?', @supplier.id).order('suppliers.name ASC').each do |supplier|
+ %li= link_to supplier.name, supplier_articles_path(supplier), tabindex: -1
- unless @supplier.shared_supplier.nil?
- #import.single_column{:style => "display:none; clear:both"}
- .box_title
- %h2 Artikel importieren
- .column_content
- #search{:style => "padding-bottom:3em"}
- - form_remote_tag :url => shared_supplier_articles_path(@supplier), |
- :before => "Element.show('loader')", :success => "Element.hide('loader')", |
- :method => :get do |
- = text_field_tag :import_query, params['import_query'], :size => 10
- = submit_tag "Suchen"
- Nur aus der Region:
- = check_box_tag "regional", "1", false
- #search_results
- // "import_search_results" will be rendered
- = link_to_function "Schließen", "Element.hide('import')"
+ #import.well.well-small(style="display:none;")
+ = form_tag shared_supplier_articles_path(@supplier), method: :get, remote: true, class: 'form-search',
+ 'data-submit-onchange' => true do
+ %h3= t '.import.title'
+ = text_field_tag "search[name_contains_all]", "", class: 'input-medium search-query',
+ placeholder: t('.import.placeholder')
+ %label.checkbox
+ = check_box_tag "search[origin_equals]", "REG", false
+ = t '.import.restrict_region'
+ #search_results.clearfix
+ = link_to t('ui.close'), "#import", 'data-toggle-this' => '#import'
-.single_column{:style => 'width:100%; clear:both'}
- .box_title
- .column_content
- #links
- %b= remote_link_to "Neuer Artikel", :url => new_supplier_article_path(@supplier)
- |
- = link_to "Alle bearbeiten", edit_all_supplier_articles_path(@supplier)
- |
- = link_to "Artikel hochladen", upload_supplier_articles_path(@supplier)
- |
- = link_to_if @current_user.role_orders?, "Bestellung anlegen", {:controller => 'orders', :action => 'new', :supplier_id => @supplier }
-
- #article_filter
- #article_search_form{:style=>"display:inline;"}
- - form_remote_tag :url => supplier_articles_path(@supplier), |
- :before => "Element.show('loader')", :success => "Element.hide('loader')", |
- :method => :get do |
- %label{:for => 'article_name'} Suche im Artikelnamen:
- = text_field_tag("query", params['query'], :size => 10 )
- = submit_tag "Suchen"
-
- %form{ :action => url_for(update_selected_supplier_articles_path(@supplier)), :method => "post", :id => "articlesInListForm" }
- #table= render :partial => 'articles'
-
-#edit_article{:style => "display:none"}
+= form_tag update_selected_supplier_articles_path(@supplier), id: "articlesInListForm",
+ 'data-submit-onchange' => true do
+ #table= render 'articles'
diff --git a/app/views/articles/index.js.haml b/app/views/articles/index.js.haml
new file mode 100644
index 00000000..a66bcf54
--- /dev/null
+++ b/app/views/articles/index.js.haml
@@ -0,0 +1 @@
+$('#table').html('#{escape_javascript(render("articles"))}');
diff --git a/app/views/articles/new.js.haml b/app/views/articles/new.js.haml
new file mode 100644
index 00000000..504f5527
--- /dev/null
+++ b/app/views/articles/new.js.haml
@@ -0,0 +1,2 @@
+$('#modalContainer').html('#{j(render("form"))}');
+$('#modalContainer').modal();
diff --git a/app/views/articles/parse_upload.html.haml b/app/views/articles/parse_upload.html.haml
index 67d411d9..edd34e88 100644
--- a/app/views/articles/parse_upload.html.haml
+++ b/app/views/articles/parse_upload.html.haml
@@ -1,40 +1,9 @@
-- title "#{@supplier.name} / Artikel hochladen"
-%p
- %i
- Bitte überprüfe die eingelesenen Artikel.
- %br/
- Achtung, momentan gibt es keine Überprüfung auf doppelte Artikel.
+- title t('.title', supplier: @supplier.name)
+%p= t('.body').html_safe
-- form_tag(create_from_upload_supplier_articles_path(@supplier)) do
- %table
- %tr
- %th Nummer
- %th Name
- %th Notiz
- %th Hersteller
- %th Herkunft
- %th Einheit
- %th Nettopreis
- %th MwSt
- %th Pfand
- %th Gebindegröße
- %th Kategorie
- - for article in @articles
- - fields_for "articles[]", article do |form|
- %tr{:class => cycle('even', 'odd')}
- %td= form.text_field 'order_number', :size => 6
- %td= form.text_field 'name', :size => 0
- %td= form.text_field 'note', :size => 15
- %td= form.text_field 'manufacturer', :size => 6
- %td= form.text_field 'origin', :size => 6
- %td= form.text_field 'unit', :size => 5
- %td= form.text_field 'price', :size => 4
- %td= form.text_field 'tax', :size => 4
- %td= form.text_field 'deposit', :size => 4
- %td= form.text_field 'unit_quantity', :size => 4
- %td= form.select 'article_category_id', ArticleCategory.find(:all).collect {|a| [ a.name, a.id ] }
- %p
- = submit_tag "Speichere neue Artikel für #{@supplier.name}"
- |
- = link_to "Zurück", upload_supplier_articles_path(@supplier)
-
\ No newline at end of file
+= form_tag(create_from_upload_supplier_articles_path(@supplier)) do
+ = render 'edit_all_table'
+ .form-actions
+ = submit_tag t('.submit', supplier: @supplier.name), class: 'btn btn-primary'
+ = link_to t('ui.or_cancel'), upload_supplier_articles_path(@supplier)
+
diff --git a/app/views/articles/shared.js.haml b/app/views/articles/shared.js.haml
new file mode 100644
index 00000000..23816d7e
--- /dev/null
+++ b/app/views/articles/shared.js.haml
@@ -0,0 +1 @@
+$('#search_results').html('#{escape_javascript(render("import_search_results"))}');
diff --git a/app/views/articles/sync.html.haml b/app/views/articles/sync.html.haml
index 84ac8ad7..23683879 100644
--- a/app/views/articles/sync.html.haml
+++ b/app/views/articles/sync.html.haml
@@ -1,71 +1,70 @@
-%h1 Artikel mit externer Datenbank synchronisieren
+- title 'Artikel mit externer Datenbank synchronisieren'
-- form_tag update_all_supplier_articles_path(@supplier, :sync => "1") do
- %h2 Auslisten ...
+= form_tag update_synchronized_supplier_articles_path(@supplier) do
+ %h2= t '.outlist.title'
%p
- unless @outlisted_articles.empty?
- Folgende Artikel wurden ausgelistet und werden
- %b gelöscht:
+ = t('.outlist.body').html_safe
%ul
- for article in @outlisted_articles
%li
= 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.
- else
- %i Es müssen keine Artikel gelöscht werden.
+ %i= t '.outlist.body_skip'
%hr/
- %h2 Aktualisieren ...
+ %h2= t '.update.title'
%p
%i
%b= @updated_articles.size
- Artikel müssen aktualisiert werden:
- %p
- %i
- Jeder Artikel wird doppelt angezeigt. Die alten Werte sind grau und die Textfelder sind mit den aktuellen
- Werten vorausgefüllt.
- %br/
- Abweichungen zu den alten Artikeln sind gelb markiert.
- %table
- %tr
- %th Name
- %th Notiz
- %th Hersteller
- %th Herkunft
- %th Einheit
- %th GebGr
- %th Preis
- %th MwSt.
- %th Pfand
- %th Kategorie
- - @updated_articles.each do |@article, unequal_attributes|
- - article = Article.find(@article.id)
- %tr{:style => 'color:grey'}
- %td= article.name
- %td= article.note
- %td= article.manufacturer
- %td= article.origin
- %td= article.unit
- %td= article.unit_quantity
- %td= article.price
- %td= article.tax
- %td= article.deposit
- %td= article.article_category.name if article.article_category
+ = t '.update.update_msg'
+ = t('.update.body').html_safe
+ %table.table
+ %thead
%tr
- - fields_for 'articles[]', @article do |form|
- %td{:style => highlight_new(unequal_attributes, :name)}
- = form.text_field 'name', :size => 0
- = form.hidden_field 'shared_updated_on'
- %td{:style => highlight_new(unequal_attributes, :note)}= form.text_field 'note', :size => 15
- %td{:style => highlight_new(unequal_attributes, :manufacturer)}= form.text_field 'manufacturer', :size => 10
- %td{:style => highlight_new(unequal_attributes, :origin)}= form.text_field 'origin', :size => 5
- %td{:style => highlight_new(unequal_attributes, :unit)}= form.text_field 'unit', :size => 5
- %td{:style => highlight_new(unequal_attributes, :unit_quantity)}= form.text_field 'unit_quantity', :size => 5
- %td{:style => highlight_new(unequal_attributes, :price)}= form.text_field 'price', :size => 5
- %td{:style => highlight_new(unequal_attributes, :tax)}= form.text_field 'tax', :size => 4
- %td{:style => highlight_new(unequal_attributes, :deposit)}= form.text_field 'deposit', :size => 4
- %td= select 'article[]', 'article_category_id', ArticleCategory.find(:all).collect {|a| [ a.name, a.id ] }, { :include_blank => true }
+ %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'
+ %tbody
+ - @updated_articles.each do |updated_article, attrs|
+ - article = Article.find(updated_article.id)
+ %tr{:style => 'color:grey'}
+ %td= article.name
+ %td= article.note
+ %td= article.manufacturer
+ %td= article.origin
+ %td= article.unit
+ %td= article.unit_quantity
+ %td= article.price
+ %td= article.tax
+ %td= article.deposit
+ %td= article.article_category.name if article.article_category
+ %tr
+ = fields_for 'articles[]', updated_article do |form|
+ %td{:style => highlight_new(attrs, :name)}
+ = form.text_field 'name', :size => 0
+ = form.hidden_field 'shared_updated_on'
+ %td{:style => highlight_new(attrs, :note)}= form.text_field 'note', class: 'input-small'
+ %td{:style => highlight_new(attrs, :manufacturer)}= form.text_field 'manufacturer', class: 'input-small'
+ %td{:style => highlight_new(attrs, :origin)}= form.text_field 'origin', class: 'input-mini'
+ %td{:style => highlight_new(attrs, :unit)}= form.text_field 'unit', class: 'input-mini'
+ %td{:style => highlight_new(attrs, :unit_quantity)}= form.text_field 'unit_quantity', class: 'input-mini'
+ %td{:style => highlight_new(attrs, :price)}= form.text_field 'price', class: 'input-mini'
+ %td{:style => highlight_new(attrs, :tax)}= form.text_field 'tax', class: 'input-mini'
+ %td{:style => highlight_new(attrs, :deposit)}= form.text_field 'deposit', class: 'input-mini'
+ %td= form.select :article_category_id, ArticleCategory.all.map {|a| [ a.name, a.id ] },
+ {include_blank: true}, class: 'input-small'
%hr/
= hidden_field 'supplier', 'id'
- = submit_tag 'Alle löschen/aktualisieren'
- |
- = link_to 'Abbrechen', supplier_articles_path(@supplier)
\ No newline at end of file
+ = submit_tag t('.submit'), class: 'btn btn-primary'
+ = link_to t('ui.or_cancel'), supplier_articles_path(@supplier)
diff --git a/app/views/articles/update.js.haml b/app/views/articles/update.js.haml
new file mode 100644
index 00000000..e007307e
--- /dev/null
+++ b/app/views/articles/update.js.haml
@@ -0,0 +1,2 @@
+$('#article_#{@article.id}').replaceWith('#{escape_javascript(render(@article))}');
+$('#modalContainer').modal('hide');
diff --git a/app/views/articles/upload.html.haml b/app/views/articles/upload.html.haml
index 6c64fcb0..7cb5f4fb 100644
--- a/app/views/articles/upload.html.haml
+++ b/app/views/articles/upload.html.haml
@@ -1,23 +1,24 @@
-- title "#{@supplier.name} / Artikel hochladen"
-%p
- %i
- Die Datei muss eine Textdatei mit der Endung '.csv' sein. Die erste Zeile
- wird beim Einlesen ignoriert.
- %br/
- Die Felder müssen mit einem Semikolon (';') getrennt und der Text mit doppelten
- Anführungszeichen ("Text...") umklammert werden.
- %br/
- Als Zeichensatz wird UTF-8 erwartet.
-%p
- %i
- Korrekte Reihenfolge der Spalten:
- %br/
- = ["Status (x=ausgelistet)", "Bestellnummer", "Name", "Notiz", "Hersteller", "Herkunft", |
- "Einheit", "Preis(netto)", "MwSt", "Pfand", "Gebindegröße", |
- "Staffelmenge", "Staffelpreis", "Kategorie"].join(" | ") |
+- title t('.title', supplier: @supplier.name)
+= 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'),
+ t('.fields.season_amount'),
+ t('.fields.season_price'),
+ t('simple_form.labels.article.article_category')].join(" | ")
-#uploadArticles.uploadForm
- - form_for :articles, :url => parse_upload_supplier_articles_path(@supplier), |
- :html => { :multipart => true } do |form| |
- %p= form.file_field "file"
- %p= submit_tag "Datei hochladen"
+= form_for :articles, :url => parse_upload_supplier_articles_path(@supplier),
+ :html => { :multipart => true } do |f|
+ %label(for="articles_file")= t '.file_label'
+ = f.file_field "file"
+ .form-actions
+ = submit_tag t('.submit'), class: 'btn'
diff --git a/app/views/deliveries/_form.html.haml b/app/views/deliveries/_form.html.haml
index a533be60..5eff702d 100644
--- a/app/views/deliveries/_form.html.haml
+++ b/app/views/deliveries/_form.html.haml
@@ -1,55 +1,45 @@
-.left_column(style="width:55%")
- - form_for([@supplier,@delivery]) do |f|
- .box_title
- %h2 Lieferung anlegen
- .column_content
- = f.error_messages
- = f.hidden_field :supplier_id
- %b Lagerartikel des Lieferanten
- #stock_changes
- - f.fields_for :stock_changes do |stock_change_form|
- %p
- = stock_change_form.select :stock_article_id, stock_articles_for_select(@supplier)
- Menge
- = stock_change_form.text_field :quantity, :size => 5, :autocomplete => 'off'
- = stock_change_form.hidden_field :_delete
- = link_to_function "Artikel aus Lieferung entfernen", "$(this).previous('input').value = 1; $(this).up('p').hide();"
- %p
- = remote_link_to "Lagerartikel der Lieferung hinzufügen", :url => {:action => 'add_stock_change', :supplier_id => @supplier.id}
- %hr/
- %p
- %b= f.label :delivered_on, "Lieferdatum"
- = f.date_select :delivered_on
- %p
- %b= f.label :note, "Notiz"
- %br/
- = f.text_area :note, :size => "35x4"
- %p
- = f.submit "Lieferung speichern"
- oder
- = link_to "Abbrechen", supplier_deliveries_path(@supplier)
+- content_for :javascript do
+ :javascript
+ $(function() {
+ $('.destroy_stock_change').live('click', function() {
+ $(this).prev('input').val('1').parent().hide();
+ return false;
+ });
-.right_column{:style => "width:35%;"}
- .box_title
- %h2 Neuen Lagerartikel anlegen
- .column_content
+ $('.remove_new_stock_change').live('click', function() {
+ $(this).parent().remove();
+ return false;
+ })
+ });
+
+= simple_form_for [@supplier, @delivery], validate: true do |f|
+ = f.hidden_field :supplier_id
+ #stock_changes
+ = f.fields_for :stock_changes do |stock_change_form|
+ %p
+ = stock_change_form.select :stock_article_id, stock_articles_for_select(@supplier)
+ Menge
+ = stock_change_form.text_field :quantity, size: 5, autocomplete: 'off'
+ = stock_change_form.hidden_field :_destroy
+ = link_to t('.remove_article'), "#", class: 'destroy_stock_change'
+ %p
+ = link_to t('.add_article'), {action: 'add_stock_change', supplier_id: @supplier.id}, remote: true
+ %p
+ %small= t('.note_new_article', new_link: link_to(t('.note_new_article_link'), new_stock_article_path)).html_safe
+ %hr/
+ = f.input :delivered_on, as: :date_picker
+ = f.input :note, input_html: {size: '35x4'}
+ .form-actions
+ = f.submit class: 'btn btn-primary'
+ = link_to t('ui.or_cancel'), supplier_deliveries_path(@supplier)
+
+/
+ TODO: Fix this!!
+ .span6
+ %h2= t '.new_article.title'
%p
- :javascript
- function fillNewStockArticle(text, li) {
- new Ajax.Updater('stock_article_form', '#{url_for(:controller => "deliveries", :action => "fill_new_stock_article_form")}', {
- method: 'get',
- parameters: {article_id: li.id}
- });
- }
- Suche nach Artikeln aus dem
- %i= @supplier.name
- Katalog:
- = text_field_with_auto_complete :article, :name, {}, |
- {:url => {:controller => 'stockit', :action => 'auto_complete_for_article_name', :supplier_id => @supplier.id}, |
- :after_update_element => 'fillNewStockArticle', :method => :get} |
+ = t('.new_article.search', supplier: @supplier.name).html_safe + ': '
+ = text_field_tag 'article_name'
%hr/
#stock_article_form
- = render :partial => 'stock_article_form', :locals => {:stock_article => @supplier.stock_articles.build}
-
-%p{:style => "clear:both"}
- = link_to 'Zurück', supplier_deliveries_path(@supplier)
\ No newline at end of file
+ = render 'stock_article_form', stock_article: @supplier.stock_articles.build
diff --git a/app/views/deliveries/_stock_article_form.html.haml b/app/views/deliveries/_stock_article_form.html.haml
index 6cb13334..395be839 100644
--- a/app/views/deliveries/_stock_article_form.html.haml
+++ b/app/views/deliveries/_stock_article_form.html.haml
@@ -1,33 +1,11 @@
-- remote_form_for stock_article, :url => add_stock_article_supplier_deliveries_path(@supplier) do |form|
- = form.error_messages
- = form.hidden_field :supplier_id
-
- %p
- Name
- %br/
- = form.text_field :name
- %p
- Einheit
- %br/
- = form.text_field :unit
- %p
- Notiz
- %br/
- = form.text_field :note
- %p
- Preis
- %br/
- = form.text_field :price
- %p
- MwSt
- %br/
- = form.text_field :tax, :value => (stock_article.tax || 7.0)
- %p
- Pfand
- %br/
- = form.text_field :deposit
- %p
- Kategorie:
- = form.select :article_category_id, ArticleCategory.all(:order => 'name').collect { |c| [c.name, c.id] }
- %p
- = submit_tag "Lagerartikel speichern"
\ No newline at end of file
+= simple_form_for stock_article, url: add_stock_article_supplier_deliveries_path(@supplier), remote: true,
+ validate: true do |f|
+ = f.hidden_field :supplier_id
+ = f.input :name
+ = f.input :unit
+ = f.input :note
+ = f.input :price
+ = f.input :tax
+ = f.input :deposit
+ = f.association :article_category
+ = f.submit class: 'btn'
\ No newline at end of file
diff --git a/app/views/deliveries/_stock_change.html.haml b/app/views/deliveries/_stock_change.html.haml
index 932903da..3c5dfd5a 100644
--- a/app/views/deliveries/_stock_change.html.haml
+++ b/app/views/deliveries/_stock_change.html.haml
@@ -1,6 +1,6 @@
%p
- - fields_for "delivery[new_stock_changes][]", stock_change do |form|
+ = fields_for "delivery[new_stock_changes][]", stock_change do |form|
= form.select :stock_article_id, stock_articles_for_select(supplier)
Menge
= form.text_field :quantity, :size => 5, :autocomplete => 'off'
- = link_to_function "Artikel aus Lieferung entfernen", "$(this).up('p').remove()"
+ = link_to t('.remove_article'), "#", :class => 'remove_new_stock_change'
diff --git a/app/views/deliveries/add_stock_change.js.haml b/app/views/deliveries/add_stock_change.js.haml
new file mode 100644
index 00000000..43659e20
--- /dev/null
+++ b/app/views/deliveries/add_stock_change.js.haml
@@ -0,0 +1 @@
+$('#stock_changes').append('#{escape_javascript(render(:partial => 'stock_change', :locals => {:stock_change => StockChange.new, :supplier => @supplier}))}');
diff --git a/app/views/deliveries/edit.html.haml b/app/views/deliveries/edit.html.haml
index 7a4f975d..914993dc 100644
--- a/app/views/deliveries/edit.html.haml
+++ b/app/views/deliveries/edit.html.haml
@@ -1,3 +1,3 @@
-- title "Lieferung bearbeiten"
+- title t('.title')
-= render :partial => 'form'
\ No newline at end of file
+= render :partial => 'form'
diff --git a/app/views/deliveries/index.html.haml b/app/views/deliveries/index.html.haml
index 28a8e648..16b0388b 100644
--- a/app/views/deliveries/index.html.haml
+++ b/app/views/deliveries/index.html.haml
@@ -1,25 +1,23 @@
-- title "#{@supplier.name}/deliveries"
+- title t('.title', supplier: @supplier.name)
-%table.list{:style => "width:50em"}
+%table.table.table-striped
%thead
%tr
- %th Geliefert am
- %th Rechnungsbetrag
- %th Notiz
- %th
- %th
- %th
+ %th= t 'simple_form.labels.delivery.delivered_on'
+ %th.numeric= t 'deliveries.invoice_amount'
+ %th= t 'simple_form.labels.defaults.note'
%tbody
- for delivery in @deliveries
%tr
%td=h delivery.delivered_on
- %td= link_to_invoice(delivery)
+ %td.numeric= link_to_invoice(delivery)
%td= truncate delivery.note
- %td= link_to 'Anzeigen', [@supplier, delivery]
- %td= link_to 'Bearbeiten', edit_supplier_delivery_path(@supplier,delivery)
- %td= link_to 'Löschen', [@supplier,delivery], :confirm => 'Are you sure?', :method => :delete
+ %td
+ = link_to t('ui.show'), [@supplier, delivery], class: 'btn btn-mini'
+ = link_to t('ui.edit'), edit_supplier_delivery_path(@supplier,delivery), class: 'btn btn-mini'
+ = link_to t('ui.delete'), [@supplier,delivery], :confirm => t('.confirm_delete'), :method => :delete,
+ class: 'btn btn-mini btn-danger'
-%br/
-= link_to "Neue Lieferung für #{@supplier.name} anlegen", new_supplier_delivery_path(@supplier)
+= link_to t('.new_delivery', supplier: @supplier.name), new_supplier_delivery_path(@supplier), class: 'btn btn-primary'
|
-= link_to "Lieferantenübersicht", suppliers_path
+= link_to t('deliveries.suppliers_overview'), suppliers_path
diff --git a/app/views/deliveries/new.html.haml b/app/views/deliveries/new.html.haml
index 7ed9a1ab..2bf3e390 100644
--- a/app/views/deliveries/new.html.haml
+++ b/app/views/deliveries/new.html.haml
@@ -1,3 +1,3 @@
-- title "Neue Lieferung von #{@supplier.name}"
+- title t('.title', supplier: @supplier.name)
-= render :partial => 'form'
\ No newline at end of file
+= render 'form'
diff --git a/app/views/deliveries/show.html.haml b/app/views/deliveries/show.html.haml
index c46323f3..05a39db6 100644
--- a/app/views/deliveries/show.html.haml
+++ b/app/views/deliveries/show.html.haml
@@ -1,55 +1,52 @@
-- title "Lieferung anzeigen"
+- title t('.title')
-%p
- %b Lieferantin:
- =h @delivery.supplier.name
-%p
- %b Geliefert am:
- = @delivery.delivered_on
-%p
- %b Rechnungsbetrag:
- = link_to_invoice(@delivery)
-- if @delivery.invoice
- %p
- %b bereinigter Rechnungsbetrag:
- = number_to_currency @delivery.invoice.net_amount
-%p
- %b Notiz:
- = simple_format @delivery.note
+%dl
+ %dt= t 'simple_form.labels.delivery.supplier'
+ %dd= @delivery.supplier.name
+ %dt= t 'simple_form.labels.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'
+ %dd= simple_format @delivery.note
-%h2 Artikel
-%table.list{:style => "width:30em"}
- %tr
- %th Artikel
- %th Einheit
- %th Menge
- %th Nettopreis
- %th Summe
- - total_net, total_gross = 0,0
- - for stock_change in @delivery.stock_changes.find :all, :include => :stock_article
- - quantity = stock_change.quantity
- - sum = quantity * stock_change.stock_article.price
- - total_net += sum
- - total_gross += quantity * stock_change.stock_article.gross_price
+%h2= t '.title_articles'
+%table.table.table-striped(style="width:500px")
+ %thead
%tr
- %td= stock_change.stock_article.name
- %td= stock_change.stock_article.unit
- %td= quantity
- %td= number_to_currency stock_change.stock_article.price
- %td= number_to_currency sum
-%p
- Nettosumme:
- = number_to_currency total_net
-%p
- Bruttosumme:
- = number_to_currency total_gross
+ %th= t '.article'
+ %th= t '.unit'
+ %th.numeric= t '.amount'
+ %th.numeric= t '.price'
+ %th.numeric= t '.sum'
+ %tbody
+ - total_net, total_gross = 0,0
+ - @delivery.stock_changes.all.each do |stock_change|
+ - quantity = stock_change.quantity
+ - sum = quantity * stock_change.stock_article.price
+ - total_net += sum
+ - total_gross += quantity * stock_change.stock_article.gross_price
+ %tr
+ %td= stock_change.stock_article.name
+ %td= stock_change.stock_article.unit
+ %td.numeric= quantity
+ %td.numeric= number_to_currency stock_change.stock_article.price
+ %td.numeric= number_to_currency sum
+ %tfoot
+ %tr
+ %td(colspan="4")= t '.sum_net'
+ %td.numeric= number_to_currency total_net
+ %tr
+ %td(colspan="4")= t '.sum_gross'
+ %td.numeric= number_to_currency total_gross
+ - if @delivery.invoice
+ %tr
+ %td(colspan="4")= t '.sum_diff'
+ %td.numeric= number_to_currency total_gross - @delivery.invoice.net_amount
-- if @delivery.invoice
- %p
- %b Brutto - bereinigter Rechnungsbetrag:
- = number_to_currency total_gross - @delivery.invoice.net_amount
-
-%br/
-= link_to 'Bearbeiten', edit_supplier_delivery_path(@supplier,@delivery)
-|
-= link_to 'Lieferungsübersicht', supplier_deliveries_path(@supplier)
\ No newline at end of file
+%p
+ = link_to t('ui.edit'), edit_supplier_delivery_path(@supplier,@delivery), class: 'btn'
+ = link_to t('deliveries.suppliers_overview'), supplier_deliveries_path(@supplier)
diff --git a/app/views/feedback/_new.html.haml b/app/views/feedback/_new.html.haml
deleted file mode 100644
index 8d5eb16b..00000000
--- a/app/views/feedback/_new.html.haml
+++ /dev/null
@@ -1,8 +0,0 @@
-%h2 Fehler gefunden? Vorschlag? Idee? Kritik?
-
-- form_remote_tag :url => {:action => "create"}, :before => "Element.show('loader')", :success => "Element.hide('loader')" do
- %p
- = text_area_tag :message, nil, :size => "40x15"
- = submit_tag "Absenden"
- oder
- = link_to_function "Abbrechen", "Element.hide('ajax_box')"
\ No newline at end of file
diff --git a/app/views/feedback/_success.html.haml b/app/views/feedback/_success.html.haml
deleted file mode 100644
index 39c18ae2..00000000
--- a/app/views/feedback/_success.html.haml
+++ /dev/null
@@ -1,4 +0,0 @@
-%h2 Nachricht wurde verschickt!
-
-%p Vielen Dank, Deine Nachricht wurde soeben dem Foodcooft Team zugestellt.
-%p= link_to_function "Schließen", "Element.hide('ajax_box')"
\ No newline at end of file
diff --git a/app/views/feedback/new.html.haml b/app/views/feedback/new.html.haml
new file mode 100644
index 00000000..d2320550
--- /dev/null
+++ b/app/views/feedback/new.html.haml
@@ -0,0 +1,9 @@
+- title t('.title')
+
+%p= t('.first_paragraph')
+%p= t('.second_paragraph')
+
+= form_tag feedback_path do
+ = text_area_tag :message, nil, class: 'input-xxlarge', rows: 10, required: 'required'
+ .form-actions
+ = submit_tag t('.send'), class: 'btn btn-primary'
\ No newline at end of file
diff --git a/app/views/finance/balancing/_edit_group_order_article.html.haml b/app/views/finance/balancing/_edit_group_order_article.html.haml
deleted file mode 100644
index 3733af80..00000000
--- a/app/views/finance/balancing/_edit_group_order_article.html.haml
+++ /dev/null
@@ -1,21 +0,0 @@
-%h2 Mengenänderung
-%p
- = group_order_article.group_order.ordergroup.name
- hat von
- = group_order_article.order_article.article.name
- bekommen:
-
-- remote_form_for group_order_article, |
- :url => {:action => 'update_group_order_article', :id => group_order_article }, |
- :before => "Element.show('loader')", :success => "Element.hide('loader')" do |form| |
-
- = form.error_messages
- %p
- %b Menge:
- (Einheit:
- = group_order_article.order_article.article.unit
- )
- = form.text_field :result, :size => "6"
- = submit_tag "Speichern"
- |
- = link_to_function 'Abbrechen', "Element.hide('edit_box')"
\ No newline at end of file
diff --git a/app/views/finance/balancing/_edit_note.html.haml b/app/views/finance/balancing/_edit_note.html.haml
index 2344603a..4463c7fd 100644
--- a/app/views/finance/balancing/_edit_note.html.haml
+++ b/app/views/finance/balancing/_edit_note.html.haml
@@ -1,9 +1,10 @@
-%h2 Notiz bearbeiten
-- remote_form_for 'order', @order, :url => {:action => 'update_note', :id => @order}, |
- :before => "Element.show('loader')", :success => "Element.hide('loader')" do |form| |
- = form.error_messages
- = form.text_area "note", :size => "60x20"
- %p
- = submit_tag "Speichern"
- |
- = link_to_function 'Abbrechen', "Element.hide('edit_box')"
\ No newline at end of file
+= simple_form_for @order, url: update_note_finance_order_path(@order), remote: true, method: :put do |f|
+ .modal-header
+ = link_to t('ui.marks.close').html_safe, '#', class: 'close', data: {dismiss: 'modal'}
+ %h3 Notiz bearbeiten
+ .modal-body
+ = f.input :note, input_html: {class: 'input-xlarge'}
+ .modal-footer
+ = link_to t('ui.close'), '#', class: 'btn', data: {dismiss: 'modal'}
+ = f.submit t('ui.save'), class: 'btn btn-primary'
+
diff --git a/app/views/finance/balancing/_edit_order_article.html.haml b/app/views/finance/balancing/_edit_order_article.html.haml
deleted file mode 100644
index f20378d6..00000000
--- a/app/views/finance/balancing/_edit_order_article.html.haml
+++ /dev/null
@@ -1,7 +0,0 @@
-%h2
- Bearbeiten von
- = @order_article.article.name
-
-- remote_form_for :order_article, :url => {:action => 'update_order_article', :id => @order_article }, |
- :before => "Element.show('loader')", :success => "Element.hide('loader')" do |
- = render :partial => "order_article_form"
\ No newline at end of file
diff --git a/app/views/finance/balancing/_edit_results_by_articles.html.haml b/app/views/finance/balancing/_edit_results_by_articles.html.haml
index c33de047..0ab5e81e 100644
--- a/app/views/finance/balancing/_edit_results_by_articles.html.haml
+++ b/app/views/finance/balancing/_edit_results_by_articles.html.haml
@@ -1,22 +1,17 @@
-%p{:style => "float:left"}
- %b Lieferung bearbeiten
-%p{:style => "float:right"}
- = remote_link_to "Artikel hinzufügen", :url => {:action => "new_order_article", :id => @order}
-
-%table{:class => "ordered_articles", :style => "clear:both"}
+%table.ordered-articles.table.table-striped
%thead
%tr
- %th[sort_td_class_helper "name"]{:colspan => "1"}
- = sort_link_helper "Artikel", "name", :action => "new", :remote => false
- %th[sort_td_class_helper "order_number"]
- = sort_link_helper "Nr.", "order_number", :action => "new", :remote => false
- %th Menge
- %th GebGr * Einheit
- %th Netto
- %th Brutto
- %th MwSt
- %th Pfand
+ %th= sort_link_helper t('.article'), "name"
+ %th= sort_link_helper t('.number'), "order_number"
+ %th= t('.amount')
+ %th= t('.amount_per_unit')
+ %th= t('.net')
+ %th= t('.gross')
+ %th= t('.tax')
+ %th= t('.refund')
%th{:colspan => "2"}
+ = link_to t('.add_article'), new_finance_order_order_article_path(@order), remote: true,
+ class: 'btn btn-small'
%tbody#result_table
- for order_article in @articles
= render :partial => "order_article_result", :locals => {:order_article => order_article}
diff --git a/app/views/finance/balancing/_group_order_articles.html.haml b/app/views/finance/balancing/_group_order_articles.html.haml
index a800d393..2895ca13 100644
--- a/app/views/finance/balancing/_group_order_articles.html.haml
+++ b/app/views/finance/balancing/_group_order_articles.html.haml
@@ -1,41 +1,41 @@
%td{:colspan => "7"}
- %table
+ %table.table.table-striped
%thead
%tr
%td
- %td{:style => "width:8em"} Gruppe
- %td Einheiten
- %td Gesamtpreis
+ %td{:style => "width:8em"}= t('.group')
+ %td= t('.units')
+ %td= t('.total')
%td{:colspan => "3",:style => "width:14em"}
- = remote_link_to '[Gruppe hinzufügen]', :url => {:action => "new_group_order_article", :id => order_article}
+ = link_to t('.add_group'), new_finance_group_order_article_path(order_article_id: order_article.id),
+ remote: true, class: 'btn btn-mini'
%tbody
- - for group_order_article in order_article.group_order_articles.ordered.all(:include => [:group_order])
- %tr{:class => cycle('even', 'odd', :name => 'results')}[group_order_article]
+ - for group_order_article in order_article.group_order_articles.select { |goa| goa.result > 0 }
+ %tr[group_order_article]
%td
%td{:style=>"width:50%"}
= group_order_article.group_order.ordergroup.name
%td{:id => "group_order_article_#{group_order_article.id}_quantity", :style => "white-space:nowrap"}
= group_order_article.result
- = button_to_remote( "+", :url => {:action => "update_group_order_article_result", :id => group_order_article, :modifier => '+'}, :html => {:style => "float:left"}, :success => "Element.hide('loader');", :before => "Element.show('loader');")
- = button_to_remote( "-", :url => {:action => "update_group_order_article_result", :id => group_order_article, :modifier => '-'}, :success => "Element.hide('loader');", :before => "Element.show('loader');")
- %td.currency
+ = link_to "+", update_result_finance_group_order_article_path(group_order_article, modifier: '+'),
+ method: :put, remote: true, class: 'btn btn-mini'
+ = link_to "-", update_result_finance_group_order_article_path(group_order_article, modifier: '-'),
+ method: :put, remote: true, class: 'btn btn-mini'
+ %td.numeric
= number_to_currency(group_order_article.order_article.price.fc_price * group_order_article.result, :unit => "")
%td.actions{:style=>"width:1em"}
- = remote_link_to icon(:edit), :update => 'edit_box', |
- :url => {:action => 'edit_group_order_article', :id => group_order_article}, |
- :success => "Element.hide('loader'); Element.show('edit_box')" |
+ = link_to "Bearbeiten", edit_finance_group_order_article_path(group_order_article), remote: true,
+ class: 'btn btn-mini'
%td.actions{:style=>"width:1em"}
- = remote_link_to icon(:delete), |
- :url => {:action => 'destroy_group_order_article', :id => group_order_article}, |
- :confirm => 'Bist du sicher?', :method => 'post' |
+ = link_to "Löschen", finance_group_order_article_path(group_order_article), method: :delete,
+ remote: true, class: 'btn btn-mini btn-danger'
%td
%tfoot
- %tr{:class => cycle('even', 'odd', :name => 'results')}
+ %tr
%td
- %td{:style => "width:8em"} Summe (FC-Preis)
+ %td{:style => "width:8em"}= t('total_fc')
%td{:id => "group_orders_sum_quantity_#{order_article.id}"}
= order_article.group_orders_sum[:quantity]
- %td{:id => "group_orders_sum_price_#{order_article.id}", :class => "currency"}
+ %td.numeric{:id => "group_orders_sum_price_#{order_article.id}"}
= number_to_currency(order_article.group_orders_sum[:price], :unit => "")
- %td{:colspan => "3"}
- - reset_cycle('results')
\ No newline at end of file
+ %td{:colspan => "3"}
\ No newline at end of file
diff --git a/app/views/finance/balancing/_invoice.html.haml b/app/views/finance/balancing/_invoice.html.haml
index 2855c43d..dc1e4193 100644
--- a/app/views/finance/balancing/_invoice.html.haml
+++ b/app/views/finance/balancing/_invoice.html.haml
@@ -1,26 +1,26 @@
- if invoice
%table
%tr
- %td Rechnungsnummer:
+ %td= t('.invoice_number')
%td= invoice.number
%tr
- %td Rechnungsdatum:
+ %td= t('.invoice_date')
%td= invoice.date
%tr
- %td Rechnungsbetrag:
+ %td= t('.invoice_amount')
%td.curreny= number_to_currency invoice.amount
%tr
- %td - Pfand berechnet:
+ %td= t('.minus_refund_calculated')
%td.curreny= number_to_currency invoice.deposit
%tr
- %td + Pfand gutgeschrieben:
+ %td= t('.plus_refund_credited')
%td.curreny= number_to_currency invoice.deposit_credit
%tr
- %td pfandbereinigter Betrag:
+ %td= t('.refund_adjusted_amount')
%td.curreny= number_to_currency invoice.net_amount
%br/
- = link_to "Rechnung bearbeiten", edit_finance_invoice_path(invoice)
+ = link_to t('.edit'), edit_finance_invoice_path(invoice)
- else
Eine Rechnung für diese Bestellung anlegen:
- = link_to "Neue Rechnung erstellen", new_finance_invoice_path(:order_id => @order, :supplier_id => @order.supplier)
+ = link_to t('.new'), new_finance_invoice_path(:order_id => @order, :supplier_id => @order.supplier)
diff --git a/app/views/finance/balancing/_new_group_order_article.html.haml b/app/views/finance/balancing/_new_group_order_article.html.haml
deleted file mode 100644
index 1291ff01..00000000
--- a/app/views/finance/balancing/_new_group_order_article.html.haml
+++ /dev/null
@@ -1,17 +0,0 @@
-%h2
- Neue Gruppenmenge für
- = group_order_article.order_article.article.name
-- remote_form_for group_order_article, :url => {:action => 'create_group_order_article'}, |
- :before => "Element.show('loader')", :success => "Element.hide('loader')" do |form| |
- = form.error_messages
- %p
- Gruppe:
- = form.select :ordergroup_id, Ordergroup.all(:order => "name").collect{ |og| [og.name, og.id] }
- %p
- Menge:
- = form.text_field :result, :size => 5
- = form.hidden_field :order_article_id
- %p
- = submit_tag "Speichern"
- |
- = link_to_function 'Abbrechen', "Element.hide('edit_box')"
\ No newline at end of file
diff --git a/app/views/finance/balancing/_new_order_article.html.haml b/app/views/finance/balancing/_new_order_article.html.haml
deleted file mode 100644
index 6e52714b..00000000
--- a/app/views/finance/balancing/_new_order_article.html.haml
+++ /dev/null
@@ -1,15 +0,0 @@
-%h2
- Neuer gelieferter Artikel die Bestellung
-
-- remote_form_for :order_article, :url => {:action => 'create_order_article', :order_id => @order.id}, |
- :before => "Element.show('loader')", :success => "Element.hide('loader')" do |form| |
- %p
- Suche im Katalog
- = text_field_with_auto_complete :article, :name, {}, |
- {:url => {:action => 'auto_complete_for_article_name', :order_id => @order.id}, |
- :after_update_element => 'setHiddenId'} |
- %p
- = form.hidden_field :article_id, :id => 'hidden_id'
- = submit_tag "Neuen Artikel hinzufügen"
- |
- = link_to_function "Abbrechen", "Element.hide('edit_box')"
\ No newline at end of file
diff --git a/app/views/finance/balancing/_order_article.html.haml b/app/views/finance/balancing/_order_article.html.haml
index 11c0994d..8bc4e268 100644
--- a/app/views/finance/balancing/_order_article.html.haml
+++ b/app/views/finance/balancing/_order_article.html.haml
@@ -1,7 +1,5 @@
%td.closed
- = link_to_function order_article.article.name, |
- "Element.toggle('group_order_articles_#{order_article.id}'); |
- Element.toggleClassName(this.up('td'), 'open')" |
+ = link_to order_article.article.name, '#', 'data-toggle-this' => "#group_order_articles_#{order_article.id}"
%td= order_article.article.order_number
%td
= order_article.units_to_order
@@ -21,9 +19,8 @@
%td= order_article.price.tax
%td= order_article.price.deposit
%td
- = remote_link_to icon(:edit), |
- :url => {:action => 'edit_order_article', :id => order_article} |
+ = link_to t('ui.edit'), edit_finance_order_order_article_path(order_article.order, order_article), remote: true,
+ class: 'btn btn-mini'
%td
- = remote_link_to icon(:delete), :confirm => 'Bist du sicher?', |
- :url => {:action => 'destroy_order_article', :id => order_article}, |
- :method => :post |
+ = link_to t('ui.delete'), finance_order_order_article_path(order_article.order, order_article), method: :delete,
+ remote: true, confirm: t('.confirm'), class: 'btn btn-danger btn-mini'
diff --git a/app/views/finance/balancing/_order_article_form.html.haml b/app/views/finance/balancing/_order_article_form.html.haml
deleted file mode 100644
index 983c74f6..00000000
--- a/app/views/finance/balancing/_order_article_form.html.haml
+++ /dev/null
@@ -1,29 +0,0 @@
-- if @error
- %b= @error
-%table
- %tr
- %th Name
- %th Nr.
- %th
- %abbr{:title=>"Anzahl gelieferter Gebinde"} Menge
- %th Einheit
- %th GebGr
- %th Netto
- %th MwSt.
- %th Pfand
- %th
- %abbr{:title=>"Ändert den Preis auch für zukünftige Bestellungen"} Preisänderung (Preis/MwSt/Pfand) global anwenden
- %tr
- %td= text_field_tag 'article[name]', @order_article.article.name, :size => 20
- %td= text_field_tag 'article[order_number]', @order_article.article.order_number, :size => 3
- %td= text_field_tag 'order_article[units_to_order]', @order_article.units_to_order, :size => 5
- %td= text_field_tag 'article[unit]', @order_article.article.unit, :size => 5
- %td= text_field_tag 'price[unit_quantity]', @order_article.price.unit_quantity, :size => 3
- %td= text_field_tag 'price[price]', @order_article.price.price, :size => 3
- %td= text_field_tag 'price[tax]', @order_article.price.tax, :size => 3
- %td= text_field_tag 'price[deposit]', @order_article.price.deposit, :size => 3
- %td= check_box_tag 'price_global'
-%br/
-= submit_tag "Speichern"
-|
-= link_to_function 'Abbrechen', "Element.hide('edit_box')"
diff --git a/app/views/finance/balancing/_order_article_result.html.haml b/app/views/finance/balancing/_order_article_result.html.haml
index 16899a23..a66187ae 100644
--- a/app/views/finance/balancing/_order_article_result.html.haml
+++ b/app/views/finance/balancing/_order_article_result.html.haml
@@ -1,5 +1,5 @@
-%tr{:class => cycle('even', 'odd', :name => 'articles')}[order_article]
- = render :partial => 'order_article', :locals => {:order_article => order_article}
+%tr[order_article]
+ = render :partial => 'finance/balancing/order_article', :locals => {:order_article => order_article}
%tr{:id => "group_order_articles_#{order_article.id}", :class => "results", :style => "display:none"}
- = render :partial => 'group_order_articles', :locals => {:order_article => order_article}
\ No newline at end of file
+ = render :partial => 'finance/balancing/group_order_articles', :locals => {:order_article => order_article}
\ No newline at end of file
diff --git a/app/views/finance/balancing/_orders.html.haml b/app/views/finance/balancing/_orders.html.haml
new file mode 100644
index 00000000..01f8a1a9
--- /dev/null
+++ b/app/views/finance/balancing/_orders.html.haml
@@ -0,0 +1,26 @@
+- unless @orders.empty?
+ - if Order.finished.count > 20
+ = items_per_page
+ = pagination_links_remote @orders
+ %table.table.table-striped
+ %thead
+ %tr
+ %th= t('.name')
+ %th= t('.end')
+ %th= t('.state')
+ %th= t('.last_edited_by')
+ %th
+ %tbody
+ - @orders.each do |order|
+ %tr{:class => cycle("even","odd", :name => "order")}
+ %td= link_to truncate(order.name), new_finance_order_path(order_id: order.id)
+ %td=h format_time(order.ends) unless order.ends.nil?
+ %td= order.closed? ? t('.cleared', amount: number_to_currency(order.foodcoop_result)) : "beendet"
+ %td= order.updated_by.nil? ? '??' : order.updated_by.nick
+ %td
+ - unless order.closed?
+ = link_to t('.clear'), new_finance_order_path(order_id: order.id), class: 'btn btn-mini btn-primary'
+ = link_to t('.close'), close_direct_finance_order_path(order),
+ :confirm => t('.confirm'), :method => :put, class: 'btn btn-mini'
+- else
+ %i= t('.no_closed_orders')
\ No newline at end of file
diff --git a/app/views/finance/balancing/_summary.haml b/app/views/finance/balancing/_summary.haml
index de6a689d..e466727f 100644
--- a/app/views/finance/balancing/_summary.haml
+++ b/app/views/finance/balancing/_summary.haml
@@ -1,23 +1,31 @@
%b=h order.name
%br/
-= "von #{format_date(order.starts)} bis #{format_date(order.ends)}"
+= t('.duration', {starts: format_date(order.starts), ends: format_date(order.ends)})
%p
%table
%tr
- %td Nettobetrag:
- %td= number_to_currency(order.sum(:net))
+ %td= t('.net_amount')
+ %td.numeric= number_to_currency(order.sum(:net))
%tr
- %td Bruttobetrag:
- %td= number_to_currency(order.sum(:gross))
+ %td= t('.gross_amount')
+ %td.numeric= number_to_currency(order.sum(:gross))
%tr
- %td FC-Betrag:
- %td= number_to_currency(order.sum(:fc))
+ %td= t('.fc_amount')
+ %td.numeric= number_to_currency(order.sum(:fc))
%tr
- %td Summe der Gruppenbeträge:
- %td= number_to_currency(order.sum(:groups))
+ %td= t('.groups_amount')
+ %td.numeric= number_to_currency(order.sum(:groups))
%tr
- %td FC Gewinn ohne Aufschlag:
- %td= number_to_currency(order.profit(:without_markup => true))
+ %td
+ = t('.fc_profit')
+ %small= t('.without_extra_charge')
+ %td.numeric= number_to_currency(order.profit(:without_markup => true))
%tr
- %td FC Gewinn mit Aufschlag:
- %td#order_profit= number_to_currency(order.profit)
\ No newline at end of file
+ %td
+ = t('.fc_profit')
+ %small= t('.with_extra_charge')
+ %td#order_profit.numeric= number_to_currency(order.profit)
+#summaryChangedWarning.alert(style="display:none;")
+ %strong= t '.changed'
+ %br/
+ = link_to t('.reload'), update_summary_finance_order_path(order), remote: true
diff --git a/app/views/finance/balancing/confirm.html.haml b/app/views/finance/balancing/confirm.html.haml
index 1a6bdff5..2fb2f707 100644
--- a/app/views/finance/balancing/confirm.html.haml
+++ b/app/views/finance/balancing/confirm.html.haml
@@ -1,16 +1,10 @@
--title "Bestellung abschließen"
-%div{:style => "width: 40em"}
- %p
- Wenn die Bestellung abgeschlossen wird, werden ebenfalls alle Gruppenkonten aktualisiert.
- %br/
- Die Konten werden wie folgt belastet:
- %table.list{:style => "width:35em"}
- - for group_order in @order.group_orders
- %tr{:class => cycle('even', 'odd')}
- %td= group_order.ordergroup.name
- %td= number_to_currency(group_order.price)
- %p
- %div{:style => "float:left"}
- = button_to "Abschließen", :action => "close", :id => @order
- %div{:style => "float:right"}
- = link_to 'Zurück zur Abrechnung', :action => 'new', :id => @order
\ No newline at end of file
+-title t('.title')
+%p!= t('.first_paragraph')
+%table.table.table-striped{:style => "width:35em"}
+ - for group_order in @order.group_orders
+ %tr{:class => cycle('even', 'odd')}
+ %td= group_order.ordergroup.name
+ %td.numeric= number_to_currency(group_order.price)
+.form-actions
+ = link_to t('.clear'), close_finance_order_path(@order), method: :put, class: 'btn btn-primary'
+ = link_to t('.or_cancle'), new_finance_order_path(order_id: @order.id)
\ No newline at end of file
diff --git a/app/views/finance/balancing/edit_note.js.haml b/app/views/finance/balancing/edit_note.js.haml
new file mode 100644
index 00000000..e64bf6db
--- /dev/null
+++ b/app/views/finance/balancing/edit_note.js.haml
@@ -0,0 +1,2 @@
+$('#modalContainer').html('#{j(render("edit_note"))}');
+$('#modalContainer').modal();
\ No newline at end of file
diff --git a/app/views/finance/balancing/index.haml b/app/views/finance/balancing/index.haml
deleted file mode 100644
index 46e0020d..00000000
--- a/app/views/finance/balancing/index.haml
+++ /dev/null
@@ -1,63 +0,0 @@
-%h1 Finanzbereich
-.left_column{:style => 'width: 50%'}
- .box_title
- %h2 Unbezahlte Rechnungen
- .column_content
- %p= link_to "Zeige alle Rechnungen", finance_invoices_path
- %table.list
- %thead
- %tr
- %th Datum
- %th Betrag
- %th Lieferantin
- %th
- %tbody
- - for invoice in @unpaid_invoices
- %tr{:class => cycle("even","odd", :name => "invoices")}
- %td= format_date(invoice.date)
- %td= number_to_currency(invoice.amount)
- %td=h invoice.supplier.name
- %td= link_to "Bearbeiten", edit_finance_invoice_path(invoice)
-
- .box_title
- %h2 letzte Überweisungen
- .column_content
- %p
- = link_to "Bestellgruppen", :controller => 'finance/transactions'
- %table.list
- %thead
- %tr
- %th Datum
- %th Gruppe
- %th Notiz
- %th Betrag
- %tbody
- - @financial_transactions.each do |ft|
- %tr{:class => cycle("even","odd", :name => "financial_transaction")}
- %td= format_date(ft.created_on)
- %td= ft.ordergroup.name
- %td{:style => "width:50%"}=h ft.note
- %td{:style => "color:#{ft.amount < 0 ? 'red' : 'black'}", :class => "currency"}= number_to_currency(ft.amount)
-
-.right_column{:style => 'width: 46%'}
- .box_title
- %h2 noch nicht abgerechnet
- .column_content
- %p= link_to "Bestellungsübersicht", :controller => 'balancing', :action => 'list'
- - unless @orders.empty?
- %table.list
- %thead
- %tr
- %th Lieferantin
- %th Ende
- %th Betrag(FC)
- %th
- %tbody
- - @orders.each do |order|
- %tr{:class => cycle("even","odd", :name => "order")}
- %td= order.name
- %td= format_date(order.ends)
- %td{:class => "currency"}= number_to_currency(order.sum(:fc))
- %td= link_to "abrechnen", :action => "new", :id => order
- - else
- Super, alles schon abgerechnet...
\ No newline at end of file
diff --git a/app/views/finance/balancing/index.html.haml b/app/views/finance/balancing/index.html.haml
new file mode 100644
index 00000000..5d2d62ea
--- /dev/null
+++ b/app/views/finance/balancing/index.html.haml
@@ -0,0 +1,3 @@
+- title t('.title')
+
+#ordersTable= render 'orders'
\ No newline at end of file
diff --git a/app/views/finance/balancing/index.js.haml b/app/views/finance/balancing/index.js.haml
new file mode 100644
index 00000000..eeb0ed06
--- /dev/null
+++ b/app/views/finance/balancing/index.js.haml
@@ -0,0 +1 @@
+$('#ordersTable').html('#{j(render('orders'))}');
\ No newline at end of file
diff --git a/app/views/finance/balancing/list.html.haml b/app/views/finance/balancing/list.html.haml
deleted file mode 100644
index 861c1e99..00000000
--- a/app/views/finance/balancing/list.html.haml
+++ /dev/null
@@ -1,32 +0,0 @@
-- title "beendete Bestellungen"
-%p{:style => "width:30em"}
- %i
- Beschreibungstext für die Abrechnunsmodi ....
-.left_column{:style => "width:70em"}
- .box_title
- .column_content
- - unless @orders.empty?
- = will_paginate @orders
- %table.list
- %thead
- %tr
- %th Name
- %th Ende
- %th Status
- %th zuletzt bearbeitet von
- %th
- %tbody
- - @orders.each do |order|
- %tr{:class => cycle("even","odd", :name => "order")}
- %td= link_to truncate(order.name), :action => "new", :id => order
- %td=h format_time(order.ends) unless order.ends.nil?
- %td= order.closed? ? "abgerechnet (#{number_to_currency order.foodcoop_result})" : "beendet"
- %td= order.updated_by.nil? ? '??' : order.updated_by.nick
- %td
- - unless order.closed?
- = link_to "abrechnen", :action => "new", :id => order
- |
- = link_to 'direkt schließen', {:action => 'close_direct', :id => order}, |
- :confirm => 'Wirklich die Bestellung schließen setzen?', :method => "post" |
- - else
- %i derzeit gibt es keine beendeten Bestellungen
\ No newline at end of file
diff --git a/app/views/finance/balancing/new.html.haml b/app/views/finance/balancing/new.html.haml
index 49d7870c..7384f50a 100644
--- a/app/views/finance/balancing/new.html.haml
+++ b/app/views/finance/balancing/new.html.haml
@@ -1,58 +1,47 @@
-- title "#{@order.name} abrechnen"
+- title t('.title', name: @order.name)
-- if @order.closed?
- %p
- %b Achtung, Bestellung wurde schon abgerechnet!
-.left_column{:style => 'width: 24em'}
- .box_title
- %h2 Zusammenfassung
- .column_content#summary
- = render :partial => "summary", :locals => {:order => @order}
+- content_for :sidebar do
+ .well.well-small
+ %h3= t('.summary')
+ #summary= render 'summary', order: @order
-- unless @order.stockit?
- .middle_column{:style => 'width: 24em'}
- .box_title
- %h2 Rechnung
- .column_content#invoice
- = render :partial => "invoice", :locals => {:invoice => @order.invoice}
+ .well.well-small
+ %h3= t('.invoice')
+ #invoice= render 'invoice', invoice: @order.invoice
-.right_column{:style => 'width: 20em'}
- .box_title
- %h2 Aktionen
- .column_content
- %ul
- - unless @order.invoice or @order.stockit?
- %li= link_to "Rechnung anlegen", new_finance_invoice_path(:order_id => @order, :supplier_id => @order.supplier)
- - unless @order.closed?
- %li= link_to "Bestellung abschließen", :action => "confirm", :id => @order
-
-.right_column{:style => 'clear:both;width: 28%'}
- .box_title
- %h2 Notizen/Protokoll
- .column_content
+ .well.well-small
+ %h3= t('.notes_and_journal')
#note
- unless @order.note.empty?
= simple_format @order.note
- else
- %p Hier kannst Du deine Abrechnung kommentieren
- = remote_link_to "Notiz bearbeiten", |
- :update => 'edit_box', :url => {:action => 'edit_note', :id => @order}, |
- :success => "Element.hide('loader'); Element.show('edit_box')" |
- .box_title
- %h2 Kommentare
- .column_content
- #comments
- = render :partial => 'shared/comments'
-
-.left_column{:style => 'width: 69%'}
- .box_title
- #editOrderNav
- %ul
- %li= remote_link_to 'Gruppenübersicht', :update => 'results', :url => {:action => 'new', :id => @order, :view => 'groupsOverview'}
- %li= remote_link_to 'Artikelübersicht', :update => 'results', :url => {:action => 'new', :id => @order, :view => 'articlesOverview'}
- %li= remote_link_to 'Bestellung bearbeiten', :update => 'results', :url => {:action => 'new', :id => @order, :view => 'editResults'}
- .column_content
- #results
- = render :partial => 'edit_results_by_articles'
- %p= link_to_top
-#edit_box{:style => 'display:none'}
\ No newline at end of file
+ %p= t('.comment_on_transaction')
+ = link_to t('.edit_note'), edit_note_finance_order_path(@order), remote: true
+
+ .well.well-small
+ %h3= t('.comments')
+ #comments= render :partial => 'shared/comments', locals: {comments: @order.comments.includes(:user)}
+
+- content_for :actionbar do
+ .btn-group
+ - unless @order.invoice or @order.stockit?
+ = link_to t('.create_invoice'), new_finance_invoice_path(:order_id => @order, :supplier_id => @order.supplier),
+ class: 'btn'
+ - unless @order.closed?
+ = link_to t('.confirm_order'), confirm_finance_order_path(@order), class: 'btn btn-primary'
+
+ #editOrderNav.btn-group.pull-right
+ = link_to '#', data: {toggle: 'dropdown'}, class: 'btn dropdown-toggle' do
+ = t('.view_options')
+ %span.caret
+ %ul.dropdown-menu
+ %li= link_to t('.edit_order'), new_finance_order_path(order_id: @order.id, view: 'edit_results'),
+ remote: true
+ %li= link_to t('.groups_overview'), new_finance_order_path(order_id: @order.id, view: 'groups_overview'),
+ remote: true
+ %li= link_to t('.articles_overview'), new_finance_order_path(order_id: @order.id, view: 'articles_overview'),
+ remote: true
+
+%section#results
+ = render 'edit_results_by_articles'
+%p= link_to_top
diff --git a/app/views/finance/balancing/new.js.haml b/app/views/finance/balancing/new.js.haml
new file mode 100644
index 00000000..0bd073fd
--- /dev/null
+++ b/app/views/finance/balancing/new.js.haml
@@ -0,0 +1 @@
+$('#results').html('#{j(render(balancing_view_partial, order: @order))}');
diff --git a/app/views/finance/balancing/update_note.js.haml b/app/views/finance/balancing/update_note.js.haml
new file mode 100644
index 00000000..e51110cb
--- /dev/null
+++ b/app/views/finance/balancing/update_note.js.haml
@@ -0,0 +1,2 @@
+$('#modalContainer').modal('hide');
+$('#note').html('#{j(simple_format(@order.note))}');
diff --git a/app/views/finance/balancing/update_summary.js.haml b/app/views/finance/balancing/update_summary.js.haml
new file mode 100644
index 00000000..251c73fb
--- /dev/null
+++ b/app/views/finance/balancing/update_summary.js.haml
@@ -0,0 +1 @@
+$('#summary').html('#{j(render('finance/balancing/summary', order: @order))}');
\ No newline at end of file
diff --git a/app/views/finance/financial_transactions/_ordergroup.haml b/app/views/finance/financial_transactions/_ordergroup.haml
new file mode 100644
index 00000000..c2595c61
--- /dev/null
+++ b/app/views/finance/financial_transactions/_ordergroup.haml
@@ -0,0 +1,7 @@
+%tr.transaction
+ %td
+ = select_tag 'financial_transactions[][ordergroup_id]',
+ options_for_select(Ordergroup.order(:name).all.map { |g| [ g.name, g.id ] })
+ %td= text_field_tag 'financial_transactions[][amount]', nil, class: 'input-small'
+ %td= link_to t('.remove'), "#", :title => t('.remove_group'), 'data-remove-transaction' => true,
+ class: 'btn btn-small'
\ No newline at end of file
diff --git a/app/views/finance/financial_transactions/_transactions.html.haml b/app/views/finance/financial_transactions/_transactions.html.haml
new file mode 100644
index 00000000..ecfd1c9e
--- /dev/null
+++ b/app/views/finance/financial_transactions/_transactions.html.haml
@@ -0,0 +1,17 @@
+- if @ordergroup.financial_transactions.count > 20
+ = items_per_page
+= pagination_links_remote @financial_transactions
+%table.table.table-striped
+ %thead
+ %tr
+ %td= sort_link_helper t('.date'), "date"
+ %td= t('.who')
+ %td= sort_link_helper t('.note'), "note"
+ %td= sort_link_helper t('.amount'), "amount"
+ %tbody
+ - @financial_transactions.each do |t|
+ %tr
+ %td= format_time(t.created_on)
+ %td= h t.user.nil? ? '??' : t.user.nick
+ %td= h t.note
+ %td.currency{:style => "color:#{t.amount < 0 ? 'red' : 'black'}; width:5em"}= number_to_currency(t.amount)
diff --git a/app/views/finance/financial_transactions/index.html.haml b/app/views/finance/financial_transactions/index.html.haml
new file mode 100644
index 00000000..7de3526a
--- /dev/null
+++ b/app/views/finance/financial_transactions/index.html.haml
@@ -0,0 +1,18 @@
+- title t('.title', name: @ordergroup.name)
+
+- content_for :actionbar do
+ = link_to t('.new_transaction'), new_finance_ordergroup_transaction_path(@ordergroup), class: 'btn btn-primary'
+
+- content_for :sidebar do
+ .well.well-small
+ %strong= t('.balance', balance: number_to_currency(@ordergroup.account_balance))
+ %br/
+ %small= t('.last_updated_at', when: distance_of_time_in_words(Time.now, @ordergroup.account_updated))
+.well.well-small
+ = form_tag finance_ordergroup_transactions_path(@ordergroup), :method => :get, :remote => true,
+ 'data-submit-onchange' => true, class: 'form-search' do
+ = text_field_tag :query, params[:query], class: 'input-medium search-query',
+ placeholder: t('.search_placeholder')
+
+
+#transactions= render 'transactions'
\ No newline at end of file
diff --git a/app/views/finance/financial_transactions/index.js.haml b/app/views/finance/financial_transactions/index.js.haml
new file mode 100644
index 00000000..53f69018
--- /dev/null
+++ b/app/views/finance/financial_transactions/index.js.haml
@@ -0,0 +1 @@
+$('#transactions').html('#{escape_javascript(render("transactions"))}');
diff --git a/app/views/finance/financial_transactions/new.html.haml b/app/views/finance/financial_transactions/new.html.haml
new file mode 100644
index 00000000..fe3e43cf
--- /dev/null
+++ b/app/views/finance/financial_transactions/new.html.haml
@@ -0,0 +1,12 @@
+- title t('.title')
+
+%p!= t('.paragraph', name: @ordergroup.name)
+
+= simple_form_for @financial_transaction, :url => finance_ordergroup_transactions_path(@ordergroup),
+ :validate => true do |f|
+ = f.hidden_field :ordergroup_id
+ = f.input :amount
+ = f.input :note, :as => :text
+ .form-actions
+ = f.submit class: 'btn btn-primary'
+ = link_to t('ui.or_cancel'), finance_ordergroup_transactions_path(@ordergroup)
diff --git a/app/views/finance/financial_transactions/new_collection.html.haml b/app/views/finance/financial_transactions/new_collection.html.haml
new file mode 100644
index 00000000..324b118b
--- /dev/null
+++ b/app/views/finance/financial_transactions/new_collection.html.haml
@@ -0,0 +1,36 @@
+- title t('.title')
+
+- content_for :javascript do
+ :javascript
+ var ordergroup = "#{escape_javascript(render('ordergroup'))}"
+
+ $(function() {
+ $('a[data-remove-transaction]').live('click', function() {
+ $(this).parents('tr').remove();
+ return false;
+ });
+
+ $('a[data-add-transaction]').click(function() {
+ $('#ordergroups').append(ordergroup);
+ return false;
+ });
+ });
+
+- content_for :sidebar do
+ .well.well-small= t('.sidebar')
+
+= form_tag finance_create_transaction_collection_path do
+ %p
+ %b= t('.note')
+ = text_field_tag :note, params[:note], class: 'input-xlarge', required: 'required'
+ %p
+ %table#ordergroups{:style => "width:20em"}
+ %tr
+ %th= t('.ordergroup')
+ %th= t('.amount')
+ = render :partial => 'ordergroup', :collection => [1, 2, 3]
+ %p
+ = link_to t('.new_ordergroup'), '#', 'data-add-transaction' => true, class: 'btn'
+ .form-actions
+ = submit_tag t('.save'), class: 'btn btn-primary'
+ = link_to t('ui.or_cancel'), finance_ordergroups_path
diff --git a/app/views/finance/group_order_articles/_form.html.haml b/app/views/finance/group_order_articles/_form.html.haml
new file mode 100644
index 00000000..f606e3ac
--- /dev/null
+++ b/app/views/finance/group_order_articles/_form.html.haml
@@ -0,0 +1,11 @@
+= simple_form_for [:finance, @group_order_article], remote: true do |form|
+ = form.hidden_field :order_article_id
+ .modal-header
+ = link_to t('ui.marks.close').html_safe, '#', class: 'close', data: {dismiss: 'modal'}
+ %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}"
+ .modal-footer
+ = link_to t('ui.close'), '#', class: 'btn', data: {dismiss: 'modal'}
+ = form.submit t('ui.save'), class: 'btn btn-primary'
diff --git a/app/views/finance/group_order_articles/edit.js.haml b/app/views/finance/group_order_articles/edit.js.haml
new file mode 100644
index 00000000..35b0e7c2
--- /dev/null
+++ b/app/views/finance/group_order_articles/edit.js.haml
@@ -0,0 +1,2 @@
+$('#modalContainer').html('#{j(render("form"))}');
+$('#modalContainer').modal();
\ No newline at end of file
diff --git a/app/views/finance/group_order_articles/new.js.haml b/app/views/finance/group_order_articles/new.js.haml
new file mode 100644
index 00000000..35b0e7c2
--- /dev/null
+++ b/app/views/finance/group_order_articles/new.js.haml
@@ -0,0 +1,2 @@
+$('#modalContainer').html('#{j(render("form"))}');
+$('#modalContainer').modal();
\ No newline at end of file
diff --git a/app/views/finance/group_order_articles/update.js.haml b/app/views/finance/group_order_articles/update.js.haml
new file mode 100644
index 00000000..36e66ccd
--- /dev/null
+++ b/app/views/finance/group_order_articles/update.js.haml
@@ -0,0 +1,4 @@
+$('#modalContainer').modal('hide');
+$('#order_article_#{@order_article.id}').html('#{j(render('finance/balancing/order_article', order_article: @order_article))}');
+$('#group_order_articles_#{@order_article.id}').html('#{j(render('finance/balancing/group_order_articles', order_article: @order_article))}');
+$('#summaryChangedWarning').show();
\ No newline at end of file
diff --git a/app/views/finance/index.html.haml b/app/views/finance/index.html.haml
new file mode 100644
index 00000000..731528bd
--- /dev/null
+++ b/app/views/finance/index.html.haml
@@ -0,0 +1,60 @@
+- title t('.title')
+
+.row-fluid
+ .span6
+ %h2
+ = t('.unpaid_invoices')
+ %small= link_to t('.show_all'), finance_invoices_path
+ %table.table.table-striped
+ %thead
+ %tr
+ %th= t('.date')
+ %th.numeric= t('.amount')
+ %th= t('.supplier')
+ %th
+ %tbody
+ - for invoice in @unpaid_invoices
+ %tr
+ %td= format_date(invoice.date)
+ %td.numeric= number_to_currency(invoice.amount)
+ %td= invoice.supplier.name
+ %td= link_to t('ui.edit'), edit_finance_invoice_path(invoice), class: 'btn btn-mini'
+
+ %h2
+ = t('.last_transactions')
+ %small= link_to(t('.show_all'), finance_ordergroups_path)
+ %table.table.table-striped
+ %thead
+ %tr
+ %th= t('.date')
+ %th= t('.group')
+ %th= t('.note')
+ %th.numeric= t('.amount')
+ %tbody
+ - @financial_transactions.each do |ft|
+ %tr
+ %td= format_date(ft.created_on)
+ %td= ft.ordergroup.name
+ %td= ft.note
+ %td.numeric{:style => "color:#{ft.amount < 0 ? 'red' : 'black'}"}= number_to_currency(ft.amount)
+ .span6
+ %h2
+ = t('.open_transactions')
+ %small= link_to t('.show_all'), finance_order_index_path
+ - unless @orders.empty?
+ %table.table.table-striped
+ %thead
+ %tr
+ %th= t('.supplier')
+ %th= t('.end')
+ %th.numeric= t('.amount_fc')
+ %th
+ %tbody
+ - @orders.each do |order|
+ %tr
+ %td= order.name
+ %td= format_date(order.ends)
+ %td.numeric= number_to_currency(order.sum(:fc))
+ %td= link_to t('.clear'), new_finance_order_path(order_id: order.id), class: 'btn btn-mini'
+ - else
+ = t('.everything_cleared')
diff --git a/app/views/finance/invoices/_form.html.haml b/app/views/finance/invoices/_form.html.haml
index 95967f37..1df288ae 100644
--- a/app/views/finance/invoices/_form.html.haml
+++ b/app/views/finance/invoices/_form.html.haml
@@ -1,43 +1,20 @@
-- form_for([:finance, @invoice]) do |f|
- = f.error_messages
+= simple_form_for([:finance, @invoice]) do |f|
= f.hidden_field :delivery_id
= f.hidden_field :order_id
- if @invoice.delivery
- %p= "Diese Rechnung ist mit einer #{link_to "Lieferung", [@invoice.supplier,@invoice.delivery]} verknüpft."
+ %p= t('.linked', what_link: link_to(t('.delivery'), [@invoice.supplier,@invoice.delivery])).html_safe
- if @invoice.order
- %p= "Diese Rechnung ist mit einer #{link_to "Bestellung", @invoice.order} verknüpft."
- %p
- Lieferantin
- %br/
- = f.select :supplier_id, Supplier.all.collect { |s| [s.name, s.id] }
- %p
- Rechnungsnummer
- %br/
- = f.text_field :number
- %p
- Rechnungsdatum
- %br/
- = f.date_select :date
- %p
- Bezahlt am
- %br/
- = f.date_select :paid_on, :include_blank => true
- %p
- Rechnungsbetrag
- %br/
- = f.text_field :amount
- %p
- Pfand berechnet
- %br/
- = f.text_field :deposit
- %p
- Pfand gutgeschrieben
- %br/
- = f.text_field :deposit_credit
- %p
- Notiz
- %br/
- = f.text_area :note, :size => "28x8"
- %p
- = f.submit "Speichern"
+ %p= t('.linked', what_link: link_to(t('.order'), @invoice.order)).html_safe
+
+ = f.association :supplier, hint: false
+ = f.input :number
+ = f.input :date, as: :date_picker
+ = f.input :paid_on, as: :date_picker
+ = f.input :amount, as: :string
+ = f.input :deposit, as: :string
+ = f.input :deposit_credit, as: :string
+ = f.input :note
+ .form-actions
+ = f.submit class: 'btn'
+ = link_to t('ui.or_cancel'), :back
diff --git a/app/views/finance/invoices/_invoices.html.haml b/app/views/finance/invoices/_invoices.html.haml
new file mode 100644
index 00000000..1663c609
--- /dev/null
+++ b/app/views/finance/invoices/_invoices.html.haml
@@ -0,0 +1,31 @@
+- if Invoice.count > 20
+ = items_per_page
+= pagination_links_remote @invoices
+
+%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
+ %th
+ %tbody
+ - for invoice in @invoices
+ %tr
+ %td= link_to h(invoice.number), finance_invoice_path(invoice)
+ %td= invoice.supplier.name
+ %td= format_date invoice.date
+ %td= format_date invoice.paid_on
+ %td= number_to_currency invoice.amount
+ %td= link_to t('.delivery'), [invoice.supplier,invoice.delivery] if invoice.delivery
+ %td= link_to format_date(invoice.order.ends), new_finance_order_path(order_id: invoice.order_id) if invoice.order
+ %td= truncate(invoice.note)
+ %td= link_to t('ui.edit'), edit_finance_invoice_path(invoice), class: 'btn btn-mini'
+ %td= link_to t('ui.delete'), finance_invoice_path(invoice), :confirm => t('.confirm_delete'), :method => :delete,
+ class: 'btn btn-danger btn-mini'
diff --git a/app/views/finance/invoices/edit.html.erb b/app/views/finance/invoices/edit.html.erb
deleted file mode 100644
index 59d3a3ea..00000000
--- a/app/views/finance/invoices/edit.html.erb
+++ /dev/null
@@ -1,6 +0,0 @@
-<% title "Rechnung bearbeiten" %>
-
-<%= render :partial => 'form' %>
-
-<%= link_to "Anzeigen", [:finance, @invoice] %> |
-<%= link_to 'Zurück', finance_invoices_path %>
diff --git a/app/views/finance/invoices/edit.html.haml b/app/views/finance/invoices/edit.html.haml
new file mode 100644
index 00000000..efdfbf27
--- /dev/null
+++ b/app/views/finance/invoices/edit.html.haml
@@ -0,0 +1,2 @@
+- title t('.title')
+= render :partial => 'form'
diff --git a/app/views/finance/invoices/index.html.erb b/app/views/finance/invoices/index.html.erb
deleted file mode 100644
index b5bf8931..00000000
--- a/app/views/finance/invoices/index.html.erb
+++ /dev/null
@@ -1,38 +0,0 @@
-<% title "Rechnungen" %>
-
-
-
-
- Nummer
- Lieferantin
- Datum
- Bezahlt am
- Betrag
- Lieferung
- Bestellung
- Note
-
-
-
-
-
- <% for invoice in @invoices %>
-
- <%= link_to h(invoice.number), finance_invoice_path(invoice)%>
- <%=h invoice.supplier.name %>
- <%= format_date invoice.date %>
- <%= format_date invoice.paid_on %>
- <%= number_to_currency invoice.amount %>
- <%= link_to "Lieferung", [invoice.supplier,invoice.delivery] if invoice.delivery %>
- <%= link_to format_date(invoice.order.ends), :controller => 'balancing', :action => 'new', :id => invoice.order if invoice.order %>
- <%=h truncate(invoice.note) %>
- <%= link_to icon(:edit), edit_finance_invoice_path(invoice) %>
- <%= link_to icon(:delete), finance_invoice_path(invoice), :confirm => 'Are you sure?', :method => :delete %>
-
- <% end %>
-
-
-
-
-
-<%= link_to 'Neue Rechnung anlegen', new_finance_invoice_path %>
diff --git a/app/views/finance/invoices/index.html.haml b/app/views/finance/invoices/index.html.haml
new file mode 100644
index 00000000..d6ec176e
--- /dev/null
+++ b/app/views/finance/invoices/index.html.haml
@@ -0,0 +1,6 @@
+- title t('.title')
+
+- content_for :actionbar do
+ = link_to t('.action_new'), new_finance_invoice_path, class: 'btn btn-primary'
+
+#invoicesTable= render 'invoices'
diff --git a/app/views/finance/invoices/index.js.haml b/app/views/finance/invoices/index.js.haml
new file mode 100644
index 00000000..1228f579
--- /dev/null
+++ b/app/views/finance/invoices/index.js.haml
@@ -0,0 +1 @@
+$('#invoicesTable').html('#{j(render('invoices'))}');
\ No newline at end of file
diff --git a/app/views/finance/invoices/new.html.erb b/app/views/finance/invoices/new.html.erb
deleted file mode 100644
index 65c24e2f..00000000
--- a/app/views/finance/invoices/new.html.erb
+++ /dev/null
@@ -1,4 +0,0 @@
-<% title "Neue Rechnung anlegen" -%>
-
-<%= render :partial => 'form' %>
-<%= link_to 'Zurück', finance_invoices_path %>
diff --git a/app/views/finance/invoices/new.html.haml b/app/views/finance/invoices/new.html.haml
new file mode 100644
index 00000000..375bc917
--- /dev/null
+++ b/app/views/finance/invoices/new.html.haml
@@ -0,0 +1,3 @@
+- title t('.title')
+= render :partial => 'form'
+= link_to t('.back'), finance_invoices_path
diff --git a/app/views/finance/invoices/show.html.haml b/app/views/finance/invoices/show.html.haml
index aca0c527..c80aec9a 100644
--- a/app/views/finance/invoices/show.html.haml
+++ b/app/views/finance/invoices/show.html.haml
@@ -1,34 +1,34 @@
-- title "Rechnung #{@invoice.number}"
+- title t('.title', number: @invoice.number)
%p
- %b Lieferantin:
- =h @invoice.supplier.name
+ %b= t 'simple_form.labels.invoice.supplier'
+ = @invoice.supplier.name
- if @invoice.delivery
%p
- %b Lieferung:
- ="Diese Rechnung ist mit einer #{link_to "Lieferung", [@invoice.supplier,@invoice.delivery]} verknüpft."
+ %b= t('simple_form.labels.invoice.delivery') + ':'
+ = t('.linked', what_link: link_to(t('.delivery'), [@invoice.supplier,@invoice.delivery])).html_safe
%p
- %b Rechnungsnummer:
- =h @invoice.number
+ %b= t('simple_form.labels.invoice.number') + ':'
+ = @invoice.number
%p
- %b Datum:
- =h @invoice.date
+ %b= t('simple_form.labels.invoice.date') + ':'
+ = @invoice.date
%p
- %b Bezahlt am:
- =h @invoice.paid_on
+ %b= t('simple_form.labels.invoice.paid_on') + ':'
+ = @invoice.paid_on
%p
- %b Rechnungsbetrag:
- =h @invoice.amount
+ %b= t('simple_form.labels.invoice.amount') + ':'
+ = number_to_currency @invoice.amount
%p
- %b Pfand berechnet:
- =h @invoice.deposit
+ %b= t('simple_form.labels.invoice.deposit') + ':'
+ = number_to_currency @invoice.deposit
%p
- %b Pfand gutgeschrieben:
- =h @invoice.deposit_credit
+ %b= t('simple_form.labels.invoice.deposit_credit') + ':'
+ = number_to_currency @invoice.deposit_credit
%p
- %b Notiz:
+ %b= t('simple_form.labels.invoice.note') + ':'
=h @invoice.note
-= link_to "Bearbeiten", edit_finance_invoice_path(@invoice)
+= link_to t('ui.edit'), edit_finance_invoice_path(@invoice)
|
-= link_to "Zurück", finance_invoices_path
+= link_to t('.back'), finance_invoices_path
diff --git a/app/views/finance/order_articles/_edit.html.haml b/app/views/finance/order_articles/_edit.html.haml
new file mode 100644
index 00000000..3c63807e
--- /dev/null
+++ b/app/views/finance/order_articles/_edit.html.haml
@@ -0,0 +1,24 @@
+= simple_form_for [:finance, @order, @order_article], remote: true do |form|
+ .modal-header
+ = link_to t('ui.marks.close').html_safe, '#', class: 'close', data: {dismiss: 'modal'}
+ %h3= t '.title'
+ .modal-body
+ = form.input :units_to_order
+
+ = simple_fields_for :article, @order_article.article do |f|
+ = f.input :name
+ = f.input :order_number
+ = f.input :unit
+
+ - if @order_article.article.is_a?(StockArticle)
+ %div.alert Preise von Lagerartikeln können nicht geändert werden!
+ - else
+ = simple_fields_for :article_price, @order_article.article_price do |f|
+ = f.input :unit_quantity
+ = f.input :price
+ = f.input :tax
+ = f.input :deposit
+ = form.input :update_current_price, as: :boolean
+ .modal-footer
+ = link_to t('ui.close'), '#', class: 'btn', data: {dismiss: 'modal'}
+ = form.submit class: 'btn btn-primary'
diff --git a/app/views/finance/order_articles/_new.html.haml b/app/views/finance/order_articles/_new.html.haml
new file mode 100644
index 00000000..3cf6136e
--- /dev/null
+++ b/app/views/finance/order_articles/_new.html.haml
@@ -0,0 +1,9 @@
+= simple_form_for [:finance, @order, @order_article], remote: true do |form|
+ .modal-header
+ = link_to t('ui.marks.close').html_safe, '#', class: 'close', data: {dismiss: 'modal'}
+ %h3= t '.title'
+ .modal-body
+ = form.input :article_id, as: :select, collection: new_order_articles_collection
+ .modal-footer
+ = link_to t('ui.close'), '#', class: 'btn', data: {dismiss: 'modal'}
+ = form.submit class: 'btn btn-primary'
diff --git a/app/views/finance/order_articles/create.js.haml b/app/views/finance/order_articles/create.js.haml
new file mode 100644
index 00000000..cc43206e
--- /dev/null
+++ b/app/views/finance/order_articles/create.js.haml
@@ -0,0 +1,3 @@
+$('#modalContainer').modal('hide');
+$('#result_table').prepend('#{j(render('finance/balancing/order_article_result', order_article: @order_article))}');
+$('#summaryChangedWarning').show();
\ No newline at end of file
diff --git a/app/views/finance/order_articles/destroy.js.haml b/app/views/finance/order_articles/destroy.js.haml
new file mode 100644
index 00000000..9e431e7d
--- /dev/null
+++ b/app/views/finance/order_articles/destroy.js.haml
@@ -0,0 +1 @@
+$('#order_article_#{@order_article.id}, #group_order_articles_#{@order_article.id}').hide();
diff --git a/app/views/finance/order_articles/edit.js.haml b/app/views/finance/order_articles/edit.js.haml
new file mode 100644
index 00000000..979e34cb
--- /dev/null
+++ b/app/views/finance/order_articles/edit.js.haml
@@ -0,0 +1,2 @@
+$('#modalContainer').html('#{j(render("edit"))}');
+$('#modalContainer').modal();
\ No newline at end of file
diff --git a/app/views/finance/order_articles/new.js.haml b/app/views/finance/order_articles/new.js.haml
new file mode 100644
index 00000000..4a44300f
--- /dev/null
+++ b/app/views/finance/order_articles/new.js.haml
@@ -0,0 +1,2 @@
+$('#modalContainer').html('#{j(render("new"))}');
+$('#modalContainer').modal();
\ No newline at end of file
diff --git a/app/views/finance/order_articles/update.js.haml b/app/views/finance/order_articles/update.js.haml
new file mode 100644
index 00000000..36e66ccd
--- /dev/null
+++ b/app/views/finance/order_articles/update.js.haml
@@ -0,0 +1,4 @@
+$('#modalContainer').modal('hide');
+$('#order_article_#{@order_article.id}').html('#{j(render('finance/balancing/order_article', order_article: @order_article))}');
+$('#group_order_articles_#{@order_article.id}').html('#{j(render('finance/balancing/group_order_articles', order_article: @order_article))}');
+$('#summaryChangedWarning').show();
\ No newline at end of file
diff --git a/app/views/finance/ordergroups/_ordergroups.html.haml b/app/views/finance/ordergroups/_ordergroups.html.haml
new file mode 100644
index 00000000..a273979d
--- /dev/null
+++ b/app/views/finance/ordergroups/_ordergroups.html.haml
@@ -0,0 +1,20 @@
+- if Ordergroup.count > 20
+ = items_per_page
+= pagination_links_remote @ordergroups
+%table.table.table-striped
+ %thead
+ %tr
+ %th= sort_link_helper t('.name'), "name", :per_page => @per_page
+ %th Kontakt
+ %th.numeric= sort_link_helper t('.account_balance'), "account_balance", :per_page => @per_page
+ %th
+ %tbody
+ - for ordergroup in @ordergroups
+ %tr
+ %td= ordergroup.name
+ %td= ordergroup.contact
+ %td.numeric= number_to_currency(ordergroup.account_balance)
+ %td
+ = link_to t('.new_transaction'), new_finance_ordergroup_transaction_path(ordergroup), class: 'btn btn-mini'
+ = link_to t('.account_statement'), finance_ordergroup_transactions_path(ordergroup), class: 'btn btn-mini'
+
\ No newline at end of file
diff --git a/app/views/finance/ordergroups/index.html.haml b/app/views/finance/ordergroups/index.html.haml
new file mode 100644
index 00000000..e9c73f21
--- /dev/null
+++ b/app/views/finance/ordergroups/index.html.haml
@@ -0,0 +1,13 @@
+- title t('.title')
+
+- content_for :actionbar do
+ = link_to t('.new_transaction'), finance_new_transaction_collection_path, class: 'btn btn-primary'
+
+.well.well-small
+ = form_tag finance_ordergroups_path, :method => :get, :remote => true,
+ 'data-submit-onchange' => true, class: 'form-search' do
+ = text_field_tag :query, params[:query], class: 'input-medium search-query',
+ placeholder: t('.search_placeholder')
+
+#ordergroupsTable
+ = render :partial => "ordergroups"
\ No newline at end of file
diff --git a/app/views/finance/ordergroups/index.js.haml b/app/views/finance/ordergroups/index.js.haml
new file mode 100644
index 00000000..90a22154
--- /dev/null
+++ b/app/views/finance/ordergroups/index.js.haml
@@ -0,0 +1 @@
+$('#ordergroupsTable').html('#{escape_javascript(render("ordergroups"))}');
diff --git a/app/views/finance/transactions/_list.rhtml b/app/views/finance/transactions/_list.rhtml
deleted file mode 100644
index 5b84e606..00000000
--- a/app/views/finance/transactions/_list.rhtml
+++ /dev/null
@@ -1,42 +0,0 @@
-<% if @total == 0 %>
-
-Keine gefunden
-
-<% else %>
-
-Anzahl gefundener Transaktionen: <%= @total %>
-
-
-<%= pagination_links_remote @financial_transactions, :update => 'transactions',
- :params => {:sort => params[:sort], :query => params['query']}%>
-
-
-
-
-
-
- >
- <%= sort_link_helper "Datum", "date" %>
-
- Wer
- >
- <%= sort_link_helper "Notiz", "note" %>
-
- >
- <%= sort_link_helper "Betrag", "amount" %>
-
-
-
-
- <% @financial_transactions.each do |t| %>
- ">
- <%= format_time(t.created_on) %>
- <%=h t.user.nil? ? '??' : t.user.nick %>
- <%=h t.note %>
- <%= number_to_currency(t.amount) %>
-
- <% end %>
-
-
-
-<% end %>
\ No newline at end of file
diff --git a/app/views/finance/transactions/_ordergroup.haml b/app/views/finance/transactions/_ordergroup.haml
deleted file mode 100644
index f8f895ea..00000000
--- a/app/views/finance/transactions/_ordergroup.haml
+++ /dev/null
@@ -1,6 +0,0 @@
-%tr.transaction
- %td
- %select{:name => 'financial_transactions[][ordergroup_id]'}
- = options_for_select Ordergroup.without_deleted.all(:order => 'name').collect { |g| [ g.name, g.id ] }
- %td= text_field_tag 'financial_transactions[][amount]'
- %td= link_to_function icon(:delete), "$(this).up('.transaction').remove()", {:title => "Gruppe enfernen"}
\ No newline at end of file
diff --git a/app/views/finance/transactions/_ordergroups.html.haml b/app/views/finance/transactions/_ordergroups.html.haml
deleted file mode 100644
index daa37180..00000000
--- a/app/views/finance/transactions/_ordergroups.html.haml
+++ /dev/null
@@ -1,28 +0,0 @@
-%p
- Gefunden:
- = @total
-%p
- %table{:style => "width:100%"}
- %tr
- %td
- = pagination_links_remote @groups, :update => :ordergroups, :params => {:sort => params[:sort]}
- %td{:style => "text-align:right"}
- - if @total > 20
- = items_per_page :update => :ordergroups
-%table.list
- %thead
- %tr
- %th= sort_link_helper "Name", "name", :per_page => @per_page
- %th Kontakt
- %th= sort_link_helper "Kontostand", "account_balance", :per_page => @per_page
- %th
- %tbody
- - for group in @groups
- %tr{:class => cycle('even','odd', :name => 'groups')}
- %td= group.name
- %td= group.contact
- %td{:class => "currency", :style => "width:5em"}= number_to_currency(group.account_balance)
- %td{:class => "actions"}
- = link_to image_tag("euro_new.png", :size => "16x16", :alt => "Neue Transaktion", :border => "0"), {:action => 'new', :id => group}, {:title => "Neue Transaktion"}
- = link_to image_tag("b_browse.png", :size => "16x16", :border => "0", :alt => 'Kontoauszug'), {:action => 'list', :id => group}, {:title => "Kontoauszug"}
-
\ No newline at end of file
diff --git a/app/views/finance/transactions/index.html.haml b/app/views/finance/transactions/index.html.haml
deleted file mode 100644
index 85faa83f..00000000
--- a/app/views/finance/transactions/index.html.haml
+++ /dev/null
@@ -1,27 +0,0 @@
-- title "Konten verwalten"
-%p
- %i
- Um mehrer Transaktionen auf einmal anzulegen folge bitte diesem
- = link_to _("Link"), :action => 'new_collection'
-
-.left_column{:style=>"width:50em"}
- .box_title
- %h2 Bestellgruppen
- .column_content
- #group_filter
- %form{:name=>"sform", :action=>"", :style=>"display:inline;"}
- Suchen im Namen:
- = text_field_tag("query", params['query'], :size => 10 )
-
- = observe_field 'query', :frequency => 2, |
- :before => "Element.show('loader')", |
- :success => "Element.hide('loader')", |
- :url => {:action => 'index'}, |
- :with => 'query', |
- :update => 'ordergroups', |
- :method => :get |
- #ordergroups
- = render :partial => "ordergroups"
- %br/
- - if @current_user.role_admin?
- = link_to "Neue Bestellgruppe anlegen", new_admin_ordergroup_path
\ No newline at end of file
diff --git a/app/views/finance/transactions/list.html.erb b/app/views/finance/transactions/list.html.erb
deleted file mode 100644
index ba82160d..00000000
--- a/app/views/finance/transactions/list.html.erb
+++ /dev/null
@@ -1,26 +0,0 @@
-<% title "Kontoauszug für #{@group.name}" %>
-
-
- Kontostand: <%= number_to_currency(@group.account_balance) -%>
- (zuletzt aktualisiert vor <%= distance_of_time_in_words(Time.now, @group.account_updated) -%>)
-
-
-
Überweisungen
-
-
- <%= observe_field 'query', :frequency => 2,
- :before => "Element.show('loader')",
- :success => "Element.hide('loader')",
- :url => {:action => 'list'},
- :with => 'query',
- :update => 'transactions' %>
-
- <%= render :partial => "list" %>
-
-
<%= link_to 'Neue Transaktion', :action => 'new', :id => @group %>
-
- <%= link_to 'Gruppenübersicht', :action => 'index' %>
-
diff --git a/app/views/finance/transactions/new.html.haml b/app/views/finance/transactions/new.html.haml
deleted file mode 100644
index 5180527d..00000000
--- a/app/views/finance/transactions/new.html.haml
+++ /dev/null
@@ -1,21 +0,0 @@
-- title "Neue Transaktion"
-
-.edit_form{ :style => "width:30em" }
- - form_for @financial_transaction, :url => {:action => 'create'} do |f|
- = f.error_messages
- = f.hidden_field :ordergroup_id
- %p
- Bestellgruppe:
- %b=h @group.name
- %p
- Betrag
- %br/
- = f.text_field :amount, :size => 10
- %p
- Notiz
- %br/
- = f.text_area :note, :cols => 40, :rows => 5
- %p
- = submit_tag "Speichern"
- |
- = link_to "Abbrechen", :controller => 'transactions'
\ No newline at end of file
diff --git a/app/views/finance/transactions/new_collection.html.haml b/app/views/finance/transactions/new_collection.html.haml
deleted file mode 100644
index a2cb0ada..00000000
--- a/app/views/finance/transactions/new_collection.html.haml
+++ /dev/null
@@ -1,20 +0,0 @@
-- title "Mehrer Konten aktualisieren"
-
-- form_tag :action => "create_collection" do
- %p
- %b Notiz
- = text_field_tag "note"
- %p
- %table#Ordergroups{:style => "width:20em"}
- %tr
- %th Bestellgruppe
- %th Betrag
- = render :partial => 'ordergroup', :collection => [1, 2, 3]
-
- %p
- = link_to_function "Neue Bestellgruppe hinzufügen" do |page|
- - page.insert_html :bottom, :Ordergroups, :partial => 'ordergroup'
- %p
- = submit_tag "Transaktionen speichern"
- |
- = link_to "Abbrechen", :controller => 'finance/transactions'
\ No newline at end of file
diff --git a/app/views/foodcoop/ordergroups/_ordergroups.html.haml b/app/views/foodcoop/ordergroups/_ordergroups.html.haml
index 51137299..7c7780ee 100644
--- a/app/views/foodcoop/ordergroups/_ordergroups.html.haml
+++ b/app/views/foodcoop/ordergroups/_ordergroups.html.haml
@@ -1,25 +1,19 @@
-%p
-%table{:style => "width:100%"}
- %tr
- %td
- = pagination_links_remote @ordergroups, :update => :ordergroups
- %td{:style => "text-align:right"}
- - if @total > 20
- = items_per_page :update => :ordergroups
+- if Ordergroup.count > 20
+ = items_per_page
+= pagination_links_remote @ordergroups
-%table.list
+%table.table.table-striped
%thead
%tr
- %th Name
- %th Mitglieder
- %th zuletzt bestellt
+ %th= t '.name'
+ %th= t '.user'
+ %th= t '.last_ordered'
%tbody
- for ordergroup in @ordergroups
- %tr{:class => cycle('even','odd', :name => 'ordergroup')}
- %td= link_to h(ordergroup.name), group_message_path(ordergroup), :title => "Bestellgruppe eine Nachricht schicken"
+ %tr
+ %td= ordergroup.name
%td=h ordergroup.users.collect { |u| u.nick }.join(", ")
- %td
- - order = ordergroup.orders.first(:order => 'starts DESC')
- = order ? format_date(order.starts) : "-"
+ %td= format_date ordergroup.orders.order('orders.starts DESC').first.try(:starts)
+ %td= link_to_new_message(message_params: {group_id: ordergroup.id})
diff --git a/app/views/foodcoop/ordergroups/index.html.haml b/app/views/foodcoop/ordergroups/index.html.haml
index 94ec4281..a20bbe97 100644
--- a/app/views/foodcoop/ordergroups/index.html.haml
+++ b/app/views/foodcoop/ordergroups/index.html.haml
@@ -1,23 +1,13 @@
-%h1 Bestellgruppen der Foodcoop
+- title t('.title')
-.left_column{:style => "width:100%"}
- .box_title
- %h2 Übersicht
- .column_content
- #user_filter{:style => "margin-right:2em;"}
- %form{:id=>"sform", :action=>"", :style=>"display:inline;"}
- %label{:for => 'article_name'} Suche nach Name:
- = text_field_tag("query", params['query'], :size => 10 )
- %label{:for => 'only_active'} Nur aktive:
- = check_box_tag('only_active')
- %small (mindestens einmal in den letzten 3 Monaten bestellt)
+.well
+ = form_tag foodcoop_ordergroups_path, :method => :get, :remote => true, 'data-submit-onchange' => true,
+ class: 'form-search' do
+ = text_field_tag :name, params[:name], class: 'input-medium search-query', placeholder: t('.name')
+ %label{:for => 'only_active'}
+ = check_box_tag 'only_active', 1, params[:only_active]
+ = t '.only_active'
+ %small= t '.only_active_desc'
- = observe_form 'sform', :frequency => 2, |
- :before => "Element.show('loader')", |
- :success => "Element.hide('loader')", |
- :url => foodcoop_ordergroups_path, |
- :update => :ordergroups, |
- :method => :get |
-
- #ordergroups
- = render :partial => "ordergroups"
\ No newline at end of file
+#ordergroups
+ = render :partial => "ordergroups"
diff --git a/app/views/foodcoop/ordergroups/index.js.haml b/app/views/foodcoop/ordergroups/index.js.haml
new file mode 100644
index 00000000..e991afec
--- /dev/null
+++ b/app/views/foodcoop/ordergroups/index.js.haml
@@ -0,0 +1 @@
+$('#ordergroups').html('#{escape_javascript(render("ordergroups"))}');
diff --git a/app/views/foodcoop/users/_users.html.haml b/app/views/foodcoop/users/_users.html.haml
index 669a0020..487f15e4 100644
--- a/app/views/foodcoop/users/_users.html.haml
+++ b/app/views/foodcoop/users/_users.html.haml
@@ -1,28 +1,23 @@
-- unless params[:sort_by_ordergroups]
- %p
- %table{:style => "width:100%"}
- %tr
- %td
- = pagination_links_remote @users, :update => :users
- %td{:style => "text-align:right"}
- - if @total > 20
- = items_per_page :update => :users
-%table.list
+- if User.count > 20
+ = items_per_page
+= pagination_links_remote @users
+%table.table.table-striped
%thead
%tr
- %th Benutzername
- %th Name
- %th Email
- %th Telefon
- %th Bestellgruppe
- %th Arbeitsgruppe(n)
+ %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
%tbody
- for user in @users
- %tr{:class => cycle('even','odd', :name => 'users')}
- %td= link_to user.nick, user_message_path(user), :title => _('Send user an email')
- %td=h user.name if @current_user.role_admin? || user.settings["profile.nameIsPublic"] == '1'
- %td=h user.email if @current_user.role_admin? || user.settings["profile.emailIsPublic"] == '1'
- %td=h user.phone if @current_user.role_admin? || user.settings["profile.phoneIsPublic"] == '1'
- %td=h user.ordergroup_name
- %td=h user.workgroups.collect(&:name).join(', ')
+ %tr
+ %td= user.nick
+ %td= user.name if @current_user.role_admin? || user.settings["profile.nameIsPublic"] == '1'
+ %td= user.email if @current_user.role_admin? || user.settings["profile.emailIsPublic"] == '1'
+ %td= user.phone if @current_user.role_admin? || user.settings["profile.phoneIsPublic"] == '1'
+ %td= user.ordergroup_name
+ %td= user.workgroups.collect(&:name).join(', ')
+ %td= link_to_new_message(message_params: {mail_to: user.id})
diff --git a/app/views/foodcoop/users/index.html.haml b/app/views/foodcoop/users/index.html.haml
index 6973213d..8219cefa 100644
--- a/app/views/foodcoop/users/index.html.haml
+++ b/app/views/foodcoop/users/index.html.haml
@@ -1,32 +1,18 @@
-%h1 Mitglieder der Foodcoop
-%p
- %i
- Hier kannst Du den Mitgliedern Deiner Foodcoop eine Nachricht schreiben.
- %br/
- Damit Deine Kontaktdaten einzusehen sind, musst Du sie unter
- = link_to "Einstellungen", my_profile_path
- freigeben.
+- title t('.title')
-.left_column{:style => "width:100%"}
- .box_title
- %h2 Übersicht
- .column_content
- - unless params[:sort_by_ordergroups]
- #user_filter{:style => "float:left; margin-right:2em;"}
- %form{:name=>"sform", :action=>"", :style=>"display:inline;"}
- %label{:for => 'article_name'} Suche nach Name:
- = text_field_tag("query", params['query'], :size => 10 )
-
- = observe_field 'query', :frequency => 2, |
- :before => "Element.show('loader')", |
- :success => "Element.hide('loader')", |
- :url => foodcoop_users_path, |
- :update => :users, |
- :with => 'query', |
- :method => :get |
-
- =_ "Nach Bestellgruppen sortieren:"
- - form_tag(foodcoop_users_path, :method => "get", :style=>"display:inline;") do
- = check_box_tag :sort_by_ordergroups, 1, params[:sort_by_ordergroups], :onclick => "submit();"
- #users
- = render :partial => "users"
\ No newline at end of file
+%section
+ = t('.body', profile_link: link_to(t('.profile_link'), my_profile_path)).html_safe
+
+ .well
+ = form_tag foodcoop_users_path, :method => :get, :remote => true,
+ 'data-submit-onchange' => true, class: 'form-search' do
+
+ = text_field_tag :user_name, params[:user_name], class: 'input-medium search-query',
+ placeholder: t('.ph_name')
+ = text_field_tag :ordergroup_name, params[:ordergroup_name], class: 'input-medium search-query',
+ placeholder: t('.ph_ordergroup')
+ %button.btn
+ %i.icon-search
+
+ #users
+ = render :partial => "users"
diff --git a/app/views/foodcoop/users/index.js.haml b/app/views/foodcoop/users/index.js.haml
new file mode 100644
index 00000000..0bf47722
--- /dev/null
+++ b/app/views/foodcoop/users/index.js.haml
@@ -0,0 +1 @@
+$('#users').html('#{escape_javascript(render("users"))}');
diff --git a/app/views/foodcoop/workgroups/_workgroup.html.haml b/app/views/foodcoop/workgroups/_workgroup.html.haml
index ead035b7..38ba70fa 100644
--- a/app/views/foodcoop/workgroups/_workgroup.html.haml
+++ b/app/views/foodcoop/workgroups/_workgroup.html.haml
@@ -1,14 +1,7 @@
-.single_column{:style => "width:55em"}
- .box_title
- %h2= workgroup.name
- .column_content
- = render :partial => 'shared/group', :locals => { :group => workgroup }
- %p
- = link_to "Alle Aufgaben zeigen", :controller => "/tasks", :action => "workgroup", :id => workgroup
- |
- = link_to "Mitgliedern eine Nachricht schicken", :controller => '/messages', :action => 'group', :id => workgroup
- - if workgroup.member?(@current_user)
- |
- = link_to "Gruppe bearbeiten", edit_foodcoop_workgroup_path(workgroup)
- |
- = link_to "Mitglieder bearbeiten", memberships_foodcoop_workgroup_path(workgroup)
+%section.well
+ %h3= workgroup.name
+ = render :partial => 'shared/group', :locals => { :group => workgroup }
+ = link_to t('.show_tasks'), workgroup_tasks_path(workgroup_id: workgroup), class: 'btn'
+ = link_to_new_message message_params: {group_id: workgroup.id}
+ - if workgroup.member?(current_user)
+ = link_to t('.edit'), edit_foodcoop_workgroup_path(workgroup), class: 'btn'
diff --git a/app/views/foodcoop/workgroups/edit.html.haml b/app/views/foodcoop/workgroups/edit.html.haml
index 556bb6e2..25ad464a 100644
--- a/app/views/foodcoop/workgroups/edit.html.haml
+++ b/app/views/foodcoop/workgroups/edit.html.haml
@@ -1,16 +1,8 @@
-- title "Gruppe bearbeiten"
+- title t('.title')
-%p
- %i
- Mitglieder kannst du
- = link_to "hier", :action => "memberships", :id => @workgroup
- hinzufügen.
-
-.edit_form{:style => "width:35em"}
- - form_for [:foodcoop, @workgroup] do |@form|
- = render :partial => "shared/group_form"
-
- %p{:style => "clear:both"}
- = submit_tag 'Speichern'
- |
- = link_to "Abbrechen", foodcoop_workgroups_path
\ No newline at end of file
+%p= t('.invite_new', invite_link: link_to(t('.invite_link'), new_invite_path(id: @workgroup.id))).html_safe
+= simple_form_for [:foodcoop, @workgroup] do |f|
+ = render :partial => 'shared/group_form_fields', :locals => {:f => f}
+ .form-actions
+ = f.submit
+ = link_to t('ui.or_cancel'), foodcoop_workgroups_path
diff --git a/app/views/foodcoop/workgroups/index.html.haml b/app/views/foodcoop/workgroups/index.html.haml
index 60a469f2..3eedf90d 100644
--- a/app/views/foodcoop/workgroups/index.html.haml
+++ b/app/views/foodcoop/workgroups/index.html.haml
@@ -1,13 +1,9 @@
-%h1 Arbeitsgruppen
+- title t('.title')
+
+= t('.body').html_safe
-%p
- %i
- Das bearbeiten von Gruppen ist nur für Mitglieder der Gruppe möglich.
- %br/
- Wenn du einer Gruppe beitreten willst, dann schreib doch den Mitgliedern eine Nachricht.
-
= render :partial => "workgroup", :collection => @workgroups
-
\ No newline at end of file
+
diff --git a/app/views/foodcoop/workgroups/memberships.html.haml b/app/views/foodcoop/workgroups/memberships.html.haml
deleted file mode 100644
index 66e86694..00000000
--- a/app/views/foodcoop/workgroups/memberships.html.haml
+++ /dev/null
@@ -1 +0,0 @@
-= render "shared/memberships/members"
\ No newline at end of file
diff --git a/app/views/group_orders/_form.html.haml b/app/views/group_orders/_form.html.haml
new file mode 100644
index 00000000..0cfc0caa
--- /dev/null
+++ b/app/views/group_orders/_form.html.haml
@@ -0,0 +1,143 @@
+- content_for :javascript do
+ :javascript
+ $(function() {
+ #{data_to_js(@ordering_data)}
+ setGroupBalance(#{@ordering_data[:available_funds]});
+ setDecimalSeparator(",");
+ setToleranceBehaviour(#{FoodsoftConfig[:tolerance_is_costly]});
+ setStockit(#{@order.stockit?});
+ });
+
+- title t('.title'), false
+
+.row-fluid
+ .well.pull-left
+ %h2= @order.name
+ %dl.dl-horizontal
+ - unless @order.note.blank?
+ %dt= t '.note'
+ %dd= @order.note
+ %dt= t '.created_by'
+ %dd= link_to_user_message_if_valid(@order.created_by)
+ %dt= t '.ending'
+ %dd= format_time(@order.ends)
+ - unless @order.stockit? or @order.supplier.min_order_quantity.blank?
+ %dt= t '.min_quantity'
+ %dd= @order.supplier.min_order_quantity
+ %dt= t '.sum_amount'
+ %dd= number_to_currency @order.sum
+ %dt= t '.last_update'
+ %dd
+ = @group_order.updated_by.nick if @group_order.updated_by
+ (#{format_time(@group_order.updated_on)})
+ %dt= t '.funds'
+ %dd= number_to_currency(@ordering_data[:available_funds])
+
+ .well.pull-right
+ = render 'switch_order', current_order: @order
+
+= form_for @group_order do |f|
+ = f.hidden_field :lock_version
+ = f.hidden_field :order_id
+ = f.hidden_field :updated_by_user_id
+ = f.hidden_field :ordergroup_id
+ %table.table.table-hover
+ %thead
+ %tr
+ %th= t '.name'
+ - if @order.stockit?
+ %th{style: 'width:120px'}= t '.supplier'
+ %th{style: "width:13px;"}
+ %th{style: "width:4.5em;"}= t '.price'
+ %th{style: "width:4.5em;"}= t '.unit'
+ - unless @order.stockit?
+ %th{style: "width:70px;"}= t '.unit_missing'
+ %th#col_required= t '.amount'
+ %th#col_tolerance= t '.tolerance'
+ - else
+ %th(style="width:20px")= t '.available'
+ %th#col_required= t '.amount'
+ %th{style: "width:15px;"}= t '.sum'
+ %tbody
+ - @order.articles_grouped_by_category.each do |category, order_articles|
+ %tr.article-category
+ %td
+ = category
+ %i.icon-tag
+ %td{colspan: "9"}
+ - order_articles.each do |order_article|
+ %tr{class: "#{cycle('even', 'odd', name: 'articles')} order-article", valign: "top"}
+ %td.name= order_article.article.name
+ - if @order.stockit?
+ %td= truncate order_article.article.supplier.name, length: 15
+ %td= h order_article.article.origin
+ %td= number_to_currency(@ordering_data[:order_articles][order_article.id][:price])
+ %td= order_article.article.unit
+ %td
+ - if @order.stockit?
+ = @ordering_data[:order_articles][order_article.id][:quantity_available]
+ - else
+ %span{id: "missing_units_#{order_article.id}"}= @ordering_data[:order_articles][order_article.id][:missing_units]
+
+ %td.quantity
+ %input{id: "q_#{order_article.id}", name: "group_order[group_order_articles_attributes][#{order_article.id}][quantity]", size: "2", type: "hidden", value: @ordering_data[:order_articles][order_article.id][:quantity]}/
+ %span.used{id: "q_used_#{order_article.id}"}= @ordering_data[:order_articles][order_article.id][:used_quantity]
+ +
+ %span.unused{id: "q_unused_#{order_article.id}"}= @ordering_data[:order_articles][order_article.id][:quantity] - @ordering_data[:order_articles][order_article.id][:used_quantity]
+ %input{type: 'button', value: '+', 'data-increase_quantity' => order_article.id}
+ %input{type: 'button', value: '-', 'data-decrease_quantity' => order_article.id}
+
+ %td.tolerance{style: ('display:none' if @order.stockit?)}
+ %input{id: "t_#{order_article.id}", name: "group_order[group_order_articles_attributes][#{order_article.id}][tolerance]", size: "2", type: "hidden", value: @ordering_data[:order_articles][order_article.id][:tolerance]}/
+ - if (@ordering_data[:order_articles][order_article.id][:unit] > 1)
+ %span.used{id: "t_used_#{order_article.id}"}= @ordering_data[:order_articles][order_article.id][:used_tolerance]
+ +
+ %span.unused{id: "t_unused_#{order_article.id}"}= @ordering_data[:order_articles][order_article.id][:tolerance] - @ordering_data[:order_articles][order_article.id][:used_tolerance]
+ %input{type: 'button', value: '+', 'data-increase_tolerance' => order_article.id}
+ %input{type: 'button', value: '-', 'data-decrease_tolerance' => order_article.id}
+
+ %td{id: "td_price_#{order_article.id}", style: "text-align:right; padding-right:10px; width:4em"}
+ %span{id: "price_#{order_article.id}_display"}= number_to_currency(@ordering_data[:order_articles][order_article.id][:total_price], unit: "")
+ €
+ .article-info
+ .article-name= order_article.article.name
+ .pull-right
+ = t('.units_full') + ':'
+ %span{id: "units_#{order_article.id}"}= order_article.units_to_order
+ %br/
+ = t('.units_total') + ':'
+ %span{id: "q_total_#{order_article.id}"}= @ordering_data[:order_articles][order_article.id][:quantity] + @ordering_data[:order_articles][order_article.id][:others_quantity]
+ %br/
+ = t('.total_tolerance') + ':'
+ %span{id: "t_total_#{order_article.id}"}= @ordering_data[:order_articles][order_article.id][:tolerance] + @ordering_data[:order_articles][order_article.id][:others_tolerance]
+ %br/
+ .pull-left
+ #{t '.manufacturer'}: #{order_article.article.manufacturer}
+ %br/
+ #{t '.units'}: #{@order.stockit? ? order_article.article.quantity_available : @ordering_data[:order_articles][order_article.id][:unit]} * #{h order_article.article.unit}
+ %br/
+ #{t '.note'}: #{order_article.article.note}
+ %br/
+ #order-footer
+ #info-box
+ #total-sum
+ %table
+ %tr
+ %td= t('.total_sum_amount') + ':'
+ %td.currency
+ %span#total_price= @group_order.price
+ €
+ %tr
+ %td= t('.available_funds') + ':'
+ %td.currency= number_to_currency(@ordering_data[:available_funds])
+ %tr
+ %td= t('.new_funds') + ':'
+ %td.currency
+ %strong
+ %span#new_balance= @ordering_data[:available_funds] - @group_order.price
+ €
+ #order-button
+ = submit_tag( t('.action_save'), id: 'submit_button', class: 'btn btn-primary' )
+ #{link_to t('ui.or_cancel'), group_orders_path}
+ %input#total_balance{name: "total_balance", type: "hidden", value: @ordergroup.account_balance - @group_order.price}/
+ %input{name: "version", type: "hidden", value: @version}/
diff --git a/app/views/group_orders/_orders.html.haml b/app/views/group_orders/_orders.html.haml
new file mode 100644
index 00000000..f3137588
--- /dev/null
+++ b/app/views/group_orders/_orders.html.haml
@@ -0,0 +1,16 @@
+%table.table.table-striped
+ %thead
+ %tr
+ %th= t '.supplier'
+ %th= t '.ending'
+ %th= t '.sum'
+ %tbody
+ - for order in orders
+ - group_order = order.group_order(@ordergroup) # Get GroupOrder if possible
+ - order_class = group_order ? "" : "color:grey"
+ %tr{:class=> cycle('even', 'odd', :name => 'orders'), :style => order_class}
+ %td= group_order.present? ? link_to(order.name, group_order_path(group_order)) : order.name
+ %td= format_time(order.ends)
+ %td.numeric= group_order ? number_to_currency(group_order.price) : "--"
+- if pagination
+ = pagination_links_remote @closed_orders
diff --git a/app/views/group_orders/_switch_order.html.haml b/app/views/group_orders/_switch_order.html.haml
new file mode 100644
index 00000000..efa6e2b3
--- /dev/null
+++ b/app/views/group_orders/_switch_order.html.haml
@@ -0,0 +1,9 @@
+- orders = Order.open.reject{ |order| order == current_order }
+- unless orders.empty?
+ %h2= t '.title'
+ %ul.unstyled
+ - orders.each do |order|
+ %li
+ = link_to_ordering(order, 'data-confirm_switch_order' => true)
+ - if order.ends
+ = t '.remaining', remaining: time_ago_in_words(order.ends)
diff --git a/app/views/group_orders/archive.html.haml b/app/views/group_orders/archive.html.haml
new file mode 100644
index 00000000..6dc020f0
--- /dev/null
+++ b/app/views/group_orders/archive.html.haml
@@ -0,0 +1,13 @@
+- title t('.title', group: @ordergroup.name)
+%p
+= t('.desc', link: link_to(t('.open_orders'), group_orders_path)).html_safe
+
+.row-fluid
+ .span6
+ %h2= t '.title_open'
+ = render :partial => "orders", :locals => {:orders => Order.finished_not_closed, :pagination => false}
+
+ .span6
+ %h2= t '.title_closed'
+ #closed_orders
+ = render :partial => "orders", :locals => {:orders => @closed_orders, :pagination => true}
diff --git a/app/views/group_orders/archive.js.haml b/app/views/group_orders/archive.js.haml
new file mode 100644
index 00000000..574031d3
--- /dev/null
+++ b/app/views/group_orders/archive.js.haml
@@ -0,0 +1 @@
+$('#closed_orders').html('#{escape_javascript(render("orders", orders: @closed_orders, pagination: true))}');
diff --git a/app/views/group_orders/edit.html.haml b/app/views/group_orders/edit.html.haml
new file mode 100644
index 00000000..86842fe7
--- /dev/null
+++ b/app/views/group_orders/edit.html.haml
@@ -0,0 +1 @@
+= render 'form'
\ No newline at end of file
diff --git a/app/views/group_orders/index.html.haml b/app/views/group_orders/index.html.haml
new file mode 100644
index 00000000..20f31b2f
--- /dev/null
+++ b/app/views/group_orders/index.html.haml
@@ -0,0 +1,39 @@
+- title t('.title'), false
+
+- content_for :sidebar do
+ .well.well-small
+ // Ordergroups Account Balance
+ %h2= t '.funds.title'
+ %table.table.table-striped
+ %tr
+ %td= t('.funds.account_balance') + ':'
+ %td.numeric{:style => "width:5em"}= number_to_currency(@ordergroup.account_balance)
+ %tr
+ %td= '- ' + t('.funds.open_orders') + ':'
+ %td.numeric= number_to_currency(@ordergroup.value_of_open_orders)
+ %tr
+ %td= '- ' + t('.funds.finished_orders') + ':'
+ %td.numeric= number_to_currency(@ordergroup.value_of_finished_orders)
+ %tr
+ %th= t('.funds.available_funds') + ':'
+ %th.numeric= number_to_currency(@ordergroup.get_available_funds)
+
+= render :partial => "shared/open_orders", :locals => {:ordergroup => @ordergroup}
+
+// finished orders
+- unless Order.finished.empty?
+ %section
+ %h2= t '.finished_orders.title'
+ = render :partial => "orders", :locals => {:orders => Order.finished_not_closed, :pagination => false}
+ - if @ordergroup.value_of_finished_orders > 0
+ %p
+ = t('.finished_orders.total_sum') + ':'
+ %b= number_to_currency(@ordergroup.value_of_finished_orders)
+
+// closed orders
+- unless Order.closed.empty?
+ %section
+ %h2= t '.closed_orders.title'
+ = render :partial => "orders", :locals => {:orders => Order.closed.all(:limit => 5), :pagination => false}
+ %br/
+ = link_to t('.closed_orders.more'), archive_group_orders_path
diff --git a/app/views/group_orders/new.html.haml b/app/views/group_orders/new.html.haml
new file mode 100644
index 00000000..86842fe7
--- /dev/null
+++ b/app/views/group_orders/new.html.haml
@@ -0,0 +1 @@
+= render 'form'
\ No newline at end of file
diff --git a/app/views/group_orders/order.html.haml b/app/views/group_orders/order.html.haml
new file mode 100644
index 00000000..0d2f8c5a
--- /dev/null
+++ b/app/views/group_orders/order.html.haml
@@ -0,0 +1,88 @@
+- content_for :head do
+ = render 'data'
+
+= render :partial => 'order_head'
+
+- form_tag(:action => 'saveOrder', :id => @order) do
+ .single_column{:style => "clear:both;margin-bottom:7em;"}
+ .box_title
+ %h2= t '.title'
+ .column_content
+ %table#order.list
+ %thead
+ %tr
+ %th= t 'group_orders.form.name'
+ %th{:style => "width:13px;"}
+ %th{:style => "width:4.5em;"}= t 'group_orders.form.price'
+ %th{:style => "width:4.5em;"}= t 'group_orders.form.unit'
+ %th{:style => "width:70px;"}= t 'group_orders.form.unit_missing'
+ %th#col_required= t 'group_orders.form.amount'
+ - if not @order.stockit?
+ %th#col_tolerance= t 'group_orders.form.tolerance'
+ %th{:style => "width:15px;"}= t 'group_orders.form.sum'
+ %tbody
+ - total = 0
+ - i = 0
+ - @articles_grouped_by_category.each do |category, order_articles|
+ %tr{:style => "background-color:#EFEFEF"}
+ %td{:style => "text-align:left"}
+ %b= h category
+ %td{:colspan => "9"}
+ - order_articles.each do |order_article|
+ - if FoodsoftConfig[:tolerance_is_costly]
+ - article_total = @price[i] * (@tolerance[i] + @quantity[i])
+ - else
+ - article_total = @price[i] * @quantity[i]
+ - total += article_total
+ %tr{:class => "#{cycle('even', 'odd', :name => 'articles')} order-article", :valign => "top"}
+ %td.name= order_article.article.name
+ %td= h order_article.article.origin
+ %td= number_to_currency(@price[i])
+ %td= order_article.article.unit
+ %td
+ %span{:id => "missing_units_#{i}"}
+ - if @order.stockit?
+ - order_article.article.quantity_available
+ - else
+ - missing_units = @unit[i] - (((@quantity[i] + @others_quantity[i]) % @unit[i]) + @tolerance[i] + @others_tolerance[i])
+ - missing_units < 0 ? 0 : missing_units
+ %td.quantity
+ %input{:id => "q_#{i}", :name => "ordered[#{order_article.id}][quantity]", :size => "2", :type => "hidden", :value => @quantity[i]}/
+ %span.used{:id => "q_used_#{i}"}= @used_quantity[i]
+ +
+ %span.unused{:id => "q_unused_#{i}"}= @quantity[i] - @used_quantity[i]
+ = button_to_function('+', "increaseQuantity(#{i})")
+ = button_to_function('-', "decreaseQuantity(#{i})")
+ - unless @order.stockit?
+ %td.tolerance
+ %input{:id => "t_#{i}", :name => "ordered[#{order_article.id}][tolerance]", :size => "2", :type => "hidden", :value => @tolerance[i]}/
+ - if (@unit[i] > 1)
+ %span.used{:id => "t_used_#{i}"}= @used_tolerance[i]
+ +
+ %span.unused{:id => "t_unused_#{i}"}= @tolerance[i] - @used_tolerance[i]
+ = button_to_function('+', "increaseTolerance(#{i})")
+ = button_to_function('-', "decreaseTolerance(#{i})")
+ %td{:id => "td_price_#{i}", :style => "text-align:right; padding-right:10px; width:4em"}
+ %span{:id => "price_#{i}_display"}= number_to_currency(article_total, :unit => "")
+ €
+ .article-info
+ %h3= order_article.article.name
+ .right
+ = t('group_orders.form.units_full') + ':'
+ %span{:id => "units_#{i}"}= order_article.units_to_order
+ %br/
+ = t('group_orders.form.total_units') + ':'
+ %span{:id => "q_total_#{i}"}= @quantity[i] + @others_quantity[i]
+ %br/
+ = t('group_orders.form.total_tolerance') + ':'
+ %span{:id => "t_total_#{i}"}= @tolerance[i] + @others_tolerance[i]
+ %br/
+ .left
+ #{t 'group_orders.form.manufacturer'}: #{order_article.article.manufacturer}
+ %br/
+ #{t 'group_orders.form.units'}: #{@order.stockit? ? order_article.article.quantity_available : @unit[i]} * #{h order_article.article.unit}
+ %br/
+ #{t 'group_orders.form.note'}: #{order_article.article.note}
+ %br/
+ - i = i + 1
+ = render "order_footer", :total => total
diff --git a/app/views/group_orders/show.html.haml b/app/views/group_orders/show.html.haml
new file mode 100644
index 00000000..ed3079ca
--- /dev/null
+++ b/app/views/group_orders/show.html.haml
@@ -0,0 +1,93 @@
+- content_for :javascript do
+ :javascript
+ $(function() {
+ $('tr.ignored').hide();
+ });
+
+- title t('.title', order: @order.name)
+
+.well
+ // Order summary
+ %dl.dl-horizontal
+ %dt= t '.supplier'
+ %dd= @order.name
+ %dt= t '.note'
+ %dd= @order.note
+ %dt= t '.ending'
+ %dd= format_time(@order.ends)
+ %dt= t '.order_sum'
+ %dd
+ - if @group_order
+ = number_to_currency(@group_order.price)
+ - else
+ = t '.not_ordered'
+ - if @order.closed?
+ %p= t '.closed_by', user: @order.updated_by.nick
+ = link_to t('.comment'), "#comments"
+
+// Article box
+%section
+ %h2= t '.articles.title'
+ .column_content#result
+ - if @group_order
+ %p.pull-right= link_to t('.articles.show_hide'), '#', 'data-toggle-this' => 'tr.ignored'
+ %p= link_to(t('.articles.edit_order'), edit_group_order_path(@group_order, order_id: @order.id), class: 'btn btn-primary') if @order.open?
+ %table.table.table-hover
+ %thead
+ %tr
+ %th{style: "width:40%"}= t '.articles.name'
+ %th= t '.articles.units'
+ %th= t '.articles.unit_price'
+ %th
+ %abbr{title: t('.articles.ordered_title')}= t '.articles.ordered'
+ %th
+ %abbr{title: t('.articles.order_nopen_title')}
+ - if @order.open?
+ = t '.articles.order_open'
+ - else
+ = t '.articles.order_not_open'
+ %th= t '.articles.total_price'
+ %tbody
+ - for category_name, order_articles in @order.articles_grouped_by_category
+ %tr.article-category
+ %td
+ = category_name
+ %i.icon-tag
+ %td{colspan: "9"}
+ - order_articles.each do |oa|
+ - # get the order-results for the ordergroup
+ - r = get_order_results(oa, @group_order.id)
+ %tr{class: cycle('even', 'odd', name: 'articles') + " " + order_article_class_name(r[:quantity], r[:tolerance], r[:result])}
+ %td{style: "width:40%"}
+ = oa.article.name
+ - unless oa.article.note.blank?
+ = image_tag("lamp_grey.png", {alt: "Notiz anzeigen", size: "15x16", border: "0", onmouseover: "$('note_#{oa.id}').show();", onmouseout: "$('note_#{oa.id}').hide();"})
+ %td= "#{oa.price.unit_quantity} x #{oa.article.unit}"
+ %td= number_to_currency(oa.price.fc_price)
+ %td
+ = r[:quantity]
+ = "+ #{r[:tolerance]}" if oa.price.unit_quantity > 1
+ %td= r[:result] > 0 ? r[:result] : "0"
+ %td= number_to_currency(r[:sub_total])
+ - unless oa.article.note.blank?
+ %tr{id: "note_#{oa.id}", class: "note even", style: "display:none"}
+ %td{colspan: "6"}=h oa.article.note
+ %tr{class: cycle('even', 'odd', name: 'articles')}
+ %th{colspan: "5"}= t '.articles.sum'
+ %th= number_to_currency(@group_order.price)
+ %br/
+ = link_to_top
+ - else
+ - if @order.open?
+ = t '.articles.not_ordered_msg'
+ = link_to t('.articles.order_now'), action: "order", id: @order
+ - else
+ = t '.articles.order_closed_msg'
+
+// Comments box
+%section
+ %h2= t '.comments.title'
+ #comments
+ = render 'shared/comments', comments: @order.comments
+ #new_comment= render 'order_comments/form', order_comment: @order.comments.build(user: current_user)
+ = link_to_top
diff --git a/app/views/home/_apple_bar.html.haml b/app/views/home/_apple_bar.html.haml
new file mode 100644
index 00000000..b239af8d
--- /dev/null
+++ b/app/views/home/_apple_bar.html.haml
@@ -0,0 +1,9 @@
+= t '.points', points: apple_bar.apples
+.progress
+ %div{class: "bar bar-#{apple_bar.group_bar_state}", style: "width: #{apple_bar.group_bar_width}%"}
+
+%span.description
+ = t '.desc', amount: number_to_currency(apple_bar.mean_order_amount_per_job, :precision=>0)
+ - if FoodsoftConfig[:stop_ordering_under].present?
+ %strong= t('.warning', threshold: FoodsoftConfig[:stop_ordering_under])
+ = link_to t('.more_info'), FoodsoftConfig[:applepear_url], target: '_blank'
diff --git a/app/views/home/_start_nav.haml b/app/views/home/_start_nav.haml
index 657fab35..4f7f1b5c 100644
--- a/app/views/home/_start_nav.haml
+++ b/app/views/home/_start_nav.haml
@@ -1,44 +1,34 @@
-%h2 Direkt zu ...
-%ul
- %li
- Foodcoop
- %ul
- %li= link_to "Mitglieder", foodcoop_users_path
- %li= link_to "Meine Aufgaben", user_tasks_path
- %li= link_to "Nachricht schreiben", :controller => "messages", :action => "new"
-
- // Orders
- - has_ordergroup = !@current_user.ordergroup.nil?
- - has_orders_role = @current_user.role_orders?
- - if has_ordergroup || has_orders_role
- %li
- Bestellungen
- %ul
- - if has_ordergroup
- %li= link_to "Bestellübersicht", :controller => "ordering"
- - if has_orders_role
- %li= link_to "Bestellungen beenden", :controller => 'orders'
- // Articles
- - if @current_user.role_article_meta? || @current_user.role_suppliers?
- %li
- Artikelverwaltung
- %ul
- %li= link_to "Artikel aktualisieren", suppliers_path
- %li= link_to "Lagerverwaltung", :controller => 'stockit'
- %li= link_to "Lieferanten verwalten", suppliers_path
-
- // Finance
- - if @current_user.role_finance?
- %li
- Finanzbereich
- %ul
- %li= link_to "Konten aktualisieren", new_collection_finance_transactions_path
- %li= link_to "Bestellungen abrechnen", finance_root_path
-
- // Administration
- - if @current_user.role_admin?
- %li
- Administration
- %ul
- %li= link_to "Neue Bestellgruppe", new_admin_ordergroup_path
- %li= link_to "Neues Mitglied", new_admin_user_path
\ No newline at end of file
+.well.well-small
+ %h3= t '.title'
+ %ul.nav.nav-list
+ %li.nav-header= t '.foodcoop'
+ %li= link_to t('.members'), foodcoop_users_path
+ %li= link_to t('.tasks'), user_tasks_path
+ %li= link_to t('.write_message'), :controller => "messages", :action => "new"
+
+ - has_ordergroup = !@current_user.ordergroup.nil?
+ - has_orders_role = @current_user.role_orders?
+ - if has_ordergroup || has_orders_role
+ %li.nav-header= t '.orders.title'
+ - if has_ordergroup
+ %li= link_to t('.orders.overview'), group_orders_path
+ - if has_orders_role
+ %li= link_to t('.orders.end'), :controller => 'orders'
+ // Articles
+ - if @current_user.role_article_meta? || @current_user.role_suppliers?
+ %li.nav-header= t '.products.title'
+ %li= link_to t('.products.edit'), suppliers_path
+ %li= link_to t('.products.edit_stock'), :controller => 'stockit'
+ %li= link_to t('.products.edit_suppliers'), suppliers_path
+
+ // Finance
+ - if @current_user.role_finance?
+ %li.nav-header= t '.finances.title'
+ %li= link_to t('.finances.accounts'), finance_new_transaction_collection_path
+ %li= link_to t('.finances.settle'), finance_root_path
+
+ // Administration
+ - if @current_user.role_admin?
+ %li.nav-header= t '.admin'
+ %li= link_to t('.new_ordergroup'), new_admin_ordergroup_path
+ %li= link_to t('.new_user'), new_admin_user_path
diff --git a/app/views/home/_stats.erb b/app/views/home/_stats.erb
deleted file mode 100644
index a8f63de2..00000000
--- a/app/views/home/_stats.erb
+++ /dev/null
@@ -1,27 +0,0 @@
-<%
-max_width = 600
-
-global_avg = Ordergroup.avg_jobs_per_euro
-group_avg = @ordergroup.avg_jobs_per_euro.to_f
-
-unless global_avg == 0 or global_avg.nan?
- length_of_global_bar = max_width / 2.0
- length_of_group_bar = (group_avg / global_avg) * length_of_global_bar
-
- length_of_group_bar = max_width if length_of_group_bar > max_width
-
- color = group_avg >= global_avg ? "#78b74e" : "red"
-%>
- Engagement Deiner Bestellgruppe
-
- <%= @ordergroup.apples -%><%= " Äpfel" if length_of_group_bar > 50 -%>
-
- Durchschnittsengagement
-
- 100 Birnen
-
-
- Abgebildet ist das Verhältnis von erledigten Aufgaben zu dem Bestellvolumen Deiner Bestellgruppe im Vergleich zum Durchschnitt in der Foodcoop.
- Konkret: Pro <%= number_to_currency( (1/global_avg).round, :precision => 0 ) %> Bestellsumme solltest Du eine Aufgabe machen!
-
-<%- end -%>
diff --git a/app/views/home/index.html.haml b/app/views/home/index.html.haml
index 08cf2b12..3e70be75 100644
--- a/app/views/home/index.html.haml
+++ b/app/views/home/index.html.haml
@@ -1,77 +1,65 @@
-%h1= t('.title')
+- title t('.title'), false
-#start_nav
+- content_for(:sidebar) do
= render :partial => 'start_nav'
-.right_column{:style => "width:70%"}
- - unless @unaccepted_tasks.empty? && @next_tasks.empty? && @unassigned_tasks_number == 0
- .box_title
- %h2 Aufgaben
- .column_content
- -unless @next_tasks.empty?
- %div{:style => "float:left, margin-bottom:2em"}
- %h3 Deine Aufgaben für die nächste Woche:
- %table{:style => "width:25em"}
- -for task in @next_tasks
- %tr
- %td= format_date task.due_date
- %td
- %b= task.name
-
- - unless @unaccepted_tasks.empty?
- %h3 Aufgaben übernehmen
- Du bis für Aufgaben verantwortlich.
- = link_to "Aufgaben übernehmen/ablehnen", user_tasks_path
- - unless @unassigned_tasks_number == 0
- %h3 Offene Aufgaben
- = "Es gibt #{@unassigned_tasks_number} #{link_to 'offene Aufgabe(n)', :controller => 'tasks'}"
- %p{:style => "clear:both"}= link_to "Meine Aufgaben", user_tasks_path
+- unless @unaccepted_tasks.empty? && @next_tasks.empty? && @unassigned_tasks.size == 0
+ %section.row-fluid
+ - unless @next_tasks.empty?
+ .span3.well
+ %h4= t '.your_tasks'
+ %dl
+ - @next_tasks.each do |task|
+ %dt= l task.due_date, format: t('.due_date_format')
+ %dd= link_to task.name, task_path(task)
+ - unless @unaccepted_tasks.empty?
+ .span3.well
+ %h4= t '.tasks_move.title'
+ = t '.tasks_move.desc'
+ = link_to t('.tasks_move.action'), user_tasks_path
+ - unless @unassigned_tasks.size == 0
+ .span3.well
+ %h4= t '.tasks_open.title'
+ = t '.tasks_open.desc', size: @unassigned_tasks.size
+ = link_to t('.tasks_open.action'), tasks_path
- - if @ordergroup
- // Current orders
- = render :partial => 'shared/open_orders'
+- if current_user.ordergroup
+ = render :partial => 'shared/open_orders', :locals => {:ordergroup => current_user.ordergroup}
- // Stats
- - if @ordergroup
- .box_title
- %h2 Engagement Deiner Bestellgruppe
- .column_content
- = render "stats"
+// Stats
+- if current_user.ordergroup
+ %section
+ %h2= t '.ordergroup.title'
+ = render :partial => "apple_bar", :locals => {:apple_bar => AppleBar.new(current_user.ordergroup)}
- - unless @messages.empty?
- .box_title
- %h2 Neuste Nachrichten
- .column_content
- = render :partial => 'messages/messages', :locals => { :subject_length => 70 }
- %br/
- = link_to "Alle Nachrichten einsehen", messages_path
+- unless Message.public.empty?
+ %section
+ %h2= t '.messages.title'
+ = render 'messages/messages', messages: Message.public.order('created_at DESC').limit(5), pagination: false
+ %p= link_to t('.messages.view_all'), messages_path
- - if @ordergroup
- // Ordergroup overview
- .box_title
- %h2 Meine Bestellgruppe
- .column_content
- %p
- %b= @ordergroup.name
- |
- Verfügbares Guthaben:
- = number_to_currency(@ordergroup.get_available_funds())
- %span.description
- (Letzte Aktualisierung ist
- = distance_of_time_in_words(Time.now, @ordergroup.account_updated) + " her)"
- %h3 Letzte Transaktionen
- %table
+- if current_user.ordergroup
+ // Ordergroup overview
+ %section
+ %h2= t '.my_ordergroup.title'
+ %p
+ %b= current_user.ordergroup.name
+ = t '.my_ordergroup.funds'
+ = number_to_currency(current_user.ordergroup.get_available_funds)
+ %small= t '.my_ordergroup.last_update', when: distance_of_time_in_words(Time.now, current_user.ordergroup.account_updated)
+ %h3= t '.my_ordergroup.transactions.title'
+ %table.table.table-striped
+ %tr
+ %th= t '.my_ordergroup.transactions.when'
+ %th= t '.my_ordergroup.transactions.where'
+ %th= t '.my_ordergroup.transactions.note'
+ %th= t '.my_ordergroup.transactions.amount'
+ - for ft in current_user.ordergroup.financial_transactions.limit(5).order('created_on DESC')
%tr
- %th Wann
- %th Wer
- %th Notiz
- %th Betrag
- - for ft in @ordergroup.financial_transactions.all(:limit => 5)
- %tr{:class => cycle('even','odd')}
- %td= format_time(ft.created_on)
- %td= h(ft.user.nil? ? '?' : ft.user.nick)
- %td= h(ft.note)
- - color = ft.amount < 0 ? 'red' : 'black'
- %td{:style => "color:#{color}; width:5em", :class => "currency"}= number_to_currency(ft.amount)
- %br/
- = link_to _("mehr ..."), my_ordergroup_path
\ No newline at end of file
+ %td= format_time(ft.created_on)
+ %td= h(ft.user.nil? ? '?' : ft.user.nick)
+ %td= h(ft.note)
+ - color = ft.amount < 0 ? 'red' : 'black'
+ %td{:style => "color:#{color}; width:5em", :class => "currency"}= number_to_currency(ft.amount)
+ %br/
+ %p= link_to t('.my_ordergroup.transactions.view'), my_ordergroup_path
diff --git a/app/views/home/ordergroup.html.erb b/app/views/home/ordergroup.html.erb
deleted file mode 100644
index d9954c14..00000000
--- a/app/views/home/ordergroup.html.erb
+++ /dev/null
@@ -1,44 +0,0 @@
-Meine Bestellgruppe
-
-
<%=h @ordergroup.name %>
-
-
- Beschreibung: <%=h @ordergroup.description %>
-
-
- Verfügbares Guthaben: <%= number_to_currency(@ordergroup.get_available_funds()) %>
-
-
Personen
-
- <% for membership in @ordergroup.memberships -%>
- <%= membership.user.nick -%>
- <% end -%>
-
- <%= remote_link_to('Person einladen', :url => new_invite_path(:id => @ordergroup)) %>
-
-
-
-
-
-
Kontoauszug
-
-
-
-
-
- <%= observe_field 'query', :frequency => 2,
- :before => "Element.show('loader')",
- :success => "Element.hide('loader')",
- :url => {:action => 'ordergroup'},
- :with => 'query',
- :update => 'transactions' %>
-
- <%= render :partial => "/finance/transactions/list" %>
-
-
-
-
-
diff --git a/app/views/home/ordergroup.html.haml b/app/views/home/ordergroup.html.haml
new file mode 100644
index 00000000..d28921a4
--- /dev/null
+++ b/app/views/home/ordergroup.html.haml
@@ -0,0 +1,26 @@
+- title t('.title'), false
+
+.row-fluid
+ .span4
+ %h2= @ordergroup.name
+ .well
+ %p
+ %b= t '.description'
+ = @ordergroup.description
+ %p
+ %b= t '.funds'
+ = number_to_currency(@ordergroup.get_available_funds())
+ %h2= t '.people'
+ %ul
+ - for membership in @ordergroup.memberships
+ %li= membership.user.nick
+ = link_to t('.invite'), new_invite_path(:id => @ordergroup), :remote => true, class: 'btn btn-primary'
+ .span8
+ %h2= t('.account_summary')
+ .well.well-small
+ = form_tag my_ordergroup_path, :method => :get, :remote => true,
+ 'data-submit-onchange' => true, class: 'form-search' do
+ = text_field_tag :query, params[:query], class: 'input-medium search-query',
+ placeholder: t('.search')
+ #transactions= render "finance/financial_transactions/transactions"
+
diff --git a/app/views/home/ordergroup.js.haml b/app/views/home/ordergroup.js.haml
new file mode 100644
index 00000000..54b5ce88
--- /dev/null
+++ b/app/views/home/ordergroup.js.haml
@@ -0,0 +1 @@
+$('#transactions').html('#{j(render("finance/financial_transactions/transactions"))}');
diff --git a/app/views/home/profile.html.erb b/app/views/home/profile.html.erb
deleted file mode 100644
index 1812765c..00000000
--- a/app/views/home/profile.html.erb
+++ /dev/null
@@ -1,38 +0,0 @@
-<% title "Mein Profil" -%>
-
-
- Hier kannst Du deine Einstellungen ändern, z.b. Deine Telphonnummer oder Dein Passwort.
-
-
-
-
-
- <%= h @user.nick %>
- (Mitglied seit: <%= distance_of_time_in_words(Time.now, @user.created_on) -%>)
-
-
-
- <% form_for(@user, :url => { :action => 'update_profile'}) do |@form| %>
- <%= render :partial => 'shared/user_form' %>
-
- <%= submit_tag 'Speichern' %> | <%= link_to 'Abbrechen', :action => 'profile' %>
- <% end %>
-
-
-
-
-
-
Du bist Mitglied in folgenden Gruppen
-
-
- <% for membership in Membership.find_all_by_user_id(@user.id) %>
-
- <%= membership.group.name %>
- <% if membership.group.type != 'Ordergroup' %>
- (<%= link_to _("Mitgliedschaft beenden"), { :action => 'cancel_membership', :membership_id => membership },
- :confirm => _("Bist Du sicher, dass Du Deine Mitgliedschaft beenden willst?"), :method => :post %>)
- <% end %>
-
- <% end %>
-
-
\ No newline at end of file
diff --git a/app/views/home/profile.html.haml b/app/views/home/profile.html.haml
new file mode 100644
index 00000000..d462995a
--- /dev/null
+++ b/app/views/home/profile.html.haml
@@ -0,0 +1,23 @@
+- title t('.title'), false
+
+.row-fluid
+ .span7
+ %h3
+ = h(t('.user.title', user: @current_user.nick))
+ %small= t '.user.since', when: distance_of_time_in_words(Time.now, @current_user.created_on)
+ = simple_form_for(@current_user, :url => { :action => 'update_profile'}) do |f|
+ = render :partial => 'shared/user_form_fields', :locals => {:f => f}
+ .form-actions
+ = submit_tag t('ui.save'), class: 'btn'
+ .span5
+ %h2= t '.groups.title'
+ %table.table.table-striped
+ - @current_user.memberships.each do |membership|
+ %tr
+ %td= membership.group.name
+ %td= link_to t('.groups.invite'), new_invite_path(id: membership.group_id),
+ remote: true, class: 'btn btn-success btn-small'
+ - if membership.group.type != 'Ordergroup'
+ %td= link_to t('.groups.cancel'), cancel_membership_path(membership_id: membership),
+ confirm: t('.groups.cancel_confirm'), method: :post,
+ class: 'btn btn-danger btn-small'
diff --git a/app/views/invites/_modal_form.html.haml b/app/views/invites/_modal_form.html.haml
new file mode 100644
index 00000000..adfbd895
--- /dev/null
+++ b/app/views/invites/_modal_form.html.haml
@@ -0,0 +1,12 @@
+= simple_form_for @invite, remote: true do |form|
+ .modal-header
+ = link_to t('ui.marks.close').html_safe, '#', class: 'close', data: {dismiss: 'modal'}
+ %h3= t '.title'
+ .modal-body
+ = t('.body', group: @invite.group.name).html_safe
+ = form.hidden_field :user_id
+ = form.hidden_field :group_id
+ = form.input :email
+ .modal-footer
+ = link_to t('ui.close'), '#', class: 'btn', data: {dismiss: 'modal'}
+ = form.submit class: 'btn btn-primary'
diff --git a/app/views/invites/_new.html.haml b/app/views/invites/_new.html.haml
deleted file mode 100644
index ddf78c65..00000000
--- a/app/views/invites/_new.html.haml
+++ /dev/null
@@ -1,16 +0,0 @@
-%p
- Hier kannst du eine Person in die Gruppe
- %b=h @invite.group.name
- einladen, die noch nicht Mitglied der Foodcoop ist.
-.edit_form{:style => 'width:35em'}
- - remote_form_for @invite do |form|
- = form.error_messages :header_message => nil
- = form.hidden_field :user_id
- = form.hidden_field :group_id
- %p
- Email-Adresse:
- = form.text_field :email, :size => 40, :maxlength => 128
- %p
- = submit_tag('Einladung abschicken')
- oder
- = link_to_function "Abbrechen", "Element.hide('edit_box')"
diff --git a/app/views/invites/_success.html.haml b/app/views/invites/_success.html.haml
deleted file mode 100644
index 99bd9132..00000000
--- a/app/views/invites/_success.html.haml
+++ /dev/null
@@ -1,7 +0,0 @@
-%p
- %b= @invite.email
- wurde erfolgreich eingeladen.
-%p
- = link_to_function "Schließen", "Element.hide('edit_box')"
- oder
- = remote_link_to "Weitere Person einladen", :url => new_invite_path(:id => @invite.group)
\ No newline at end of file
diff --git a/app/views/invites/create.js.haml b/app/views/invites/create.js.haml
new file mode 100644
index 00000000..ea78f292
--- /dev/null
+++ b/app/views/invites/create.js.haml
@@ -0,0 +1 @@
+$('#modalContainer').modal('hide');
\ No newline at end of file
diff --git a/app/views/invites/new.html.haml b/app/views/invites/new.html.haml
new file mode 100644
index 00000000..eb9081cb
--- /dev/null
+++ b/app/views/invites/new.html.haml
@@ -0,0 +1,7 @@
+= t('.body', group: @invite.group.name).html_safe
+= simple_form_for @invite do |form|
+ = form.hidden_field :user_id
+ = form.hidden_field :group_id
+ = form.input :email
+ = form.submit t('.action')
+ = link_to t('.back'), :back
diff --git a/app/views/invites/new.js.haml b/app/views/invites/new.js.haml
new file mode 100644
index 00000000..c8714ca2
--- /dev/null
+++ b/app/views/invites/new.js.haml
@@ -0,0 +1,2 @@
+$('#modalContainer').html('#{j(render('modal_form'))}');
+$('#modalContainer').modal();
\ No newline at end of file
diff --git a/app/views/kaminari/_first_page.html.haml b/app/views/kaminari/_first_page.html.haml
new file mode 100644
index 00000000..90b48d12
--- /dev/null
+++ b/app/views/kaminari/_first_page.html.haml
@@ -0,0 +1,12 @@
+-#
+ Link to the "First" page
+ - available local variables
+ url: url to the first page
+ current_page: a page object for the currently displayed page
+ num_pages: total number of pages
+ per_page: number of items to fetch per page
+ remote: data-remote
+
+- unless current_page.first?
+ %li{:class => "first"}
+ = link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, :remote => remote
\ No newline at end of file
diff --git a/app/views/kaminari/_gap.html.haml b/app/views/kaminari/_gap.html.haml
new file mode 100644
index 00000000..824ae292
--- /dev/null
+++ b/app/views/kaminari/_gap.html.haml
@@ -0,0 +1,11 @@
+-#
+ Non-link tag that stands for skipped pages...
+ - available local variables
+ current_page: a page object for the currently displayed page
+ num_pages: total number of pages
+ per_page: number of items to fetch per page
+ remote: data-remote
+
+%li{:class => "page gap disabled"}
+ %a{:href => "#", :onclick => "return false;"}
+ = raw(t 'views.pagination.truncate')
\ No newline at end of file
diff --git a/app/views/kaminari/_last_page.html.haml b/app/views/kaminari/_last_page.html.haml
new file mode 100644
index 00000000..b185e96a
--- /dev/null
+++ b/app/views/kaminari/_last_page.html.haml
@@ -0,0 +1,13 @@
+-#
+ Link to the "Last" page
+ - available local variables
+ url: url to the last page
+ current_page: a page object for the currently displayed page
+ num_pages: total number of pages
+ per_page: number of items to fetch per page
+ remote: data-remote
+
+- unless current_page.last?
+ %li{:class=>"last next"}
+ -# "next" class present for border styling in twitter bootstrap %>
+ = link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, {:remote => remote}
\ No newline at end of file
diff --git a/app/views/kaminari/_next_page.html.haml b/app/views/kaminari/_next_page.html.haml
new file mode 100644
index 00000000..d3d749cd
--- /dev/null
+++ b/app/views/kaminari/_next_page.html.haml
@@ -0,0 +1,12 @@
+-#
+ Link to the "Next" page
+ - available local variables
+ url: url to the next page
+ current_page: a page object for the currently displayed page
+ num_pages: total number of pages
+ per_page: number of items to fetch per page
+ remote: data-remote
+
+- unless current_page.last?
+ %li{:class=>"next_page"}
+ = link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, :rel => 'next', :remote => remote
\ No newline at end of file
diff --git a/app/views/kaminari/_page.html.haml b/app/views/kaminari/_page.html.haml
new file mode 100644
index 00000000..6df34eb0
--- /dev/null
+++ b/app/views/kaminari/_page.html.haml
@@ -0,0 +1,11 @@
+-#
+ Link showing page number
+ - available local variables
+ page: a page object for "this" page
+ url: url to this page
+ current_page: a page object for the currently displayed page
+ num_pages: total number of pages
+ per_page: number of items to fetch per page
+ remote: data-remote
+%li{:class=>"page #{' active' if page.current? }"}
+ = link_to page, url, opts = {:remote => remote, :rel => page.next? ? 'next' : page.prev? ? 'prev' : nil}
\ No newline at end of file
diff --git a/app/views/kaminari/_paginator.html.haml b/app/views/kaminari/_paginator.html.haml
new file mode 100644
index 00000000..748b2f1a
--- /dev/null
+++ b/app/views/kaminari/_paginator.html.haml
@@ -0,0 +1,21 @@
+-#
+ The container tag
+ - available local variables
+ current_page: a page object for the currently displayed page
+ num_pages: total number of pages
+ per_page: number of items to fetch per page
+ remote: data-remote
+ paginator: the paginator that renders the pagination tags inside
+
+= paginator.render do
+ %nav.pagination
+ %ul
+ = first_page_tag unless current_page.first?
+ = prev_page_tag unless current_page.first?
+ - each_page do |page|
+ - if page.left_outer? || page.right_outer? || page.inside_window?
+ = page_tag page
+ - elsif !page.was_truncated?
+ = gap_tag
+ = next_page_tag unless current_page.last?
+ = last_page_tag unless current_page.last?
\ No newline at end of file
diff --git a/app/views/kaminari/_prev_page.html.haml b/app/views/kaminari/_prev_page.html.haml
new file mode 100644
index 00000000..662a209f
--- /dev/null
+++ b/app/views/kaminari/_prev_page.html.haml
@@ -0,0 +1,12 @@
+-#
+ Link to the "Previous" page
+ - available local variables
+ url: url to the previous page
+ current_page: a page object for the currently displayed page
+ num_pages: total number of pages
+ per_page: number of items to fetch per page
+ remote: data-remote
+
+- unless current_page.first?
+ %li{:class=>"prev"}
+ = link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, :rel => 'prev', :remote => remote
\ No newline at end of file
diff --git a/app/views/layouts/_header.html.haml b/app/views/layouts/_header.html.haml
new file mode 100644
index 00000000..c3c16327
--- /dev/null
+++ b/app/views/layouts/_header.html.haml
@@ -0,0 +1,26 @@
+!!! 5
+%html(lang='#{I18n.locale}')
+ %head
+ %meta(charset="utf-8")
+ %meta(http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1")
+ %meta(name="viewport" content="width=device-width, initial-scale=1.0")
+ %title= [t('layouts.foodsoft'), yield(:title)].join(" - ")
+ = csrf_meta_tags
+ = stylesheet_link_tag "application", :media => "all"
+ %link(href="images/apple-touch-icon-144x144.png" rel="apple-touch-icon-precomposed" sizes="144x144")
+ %link(href="images/apple-touch-icon-114x114.png" rel="apple-touch-icon-precomposed" sizes="114x114")
+ %link(href="images/apple-touch-icon-72x72.png" rel="apple-touch-icon-precomposed" sizes="72x72")
+ %link(href="images/apple-touch-icon.png" rel="apple-touch-icon-precomposed")
+ //%link(href="images/favicon.ico" rel="shortcut icon")
+
+ = yield(:head)
+
+ %body
+ = yield
+
+ /
+ Javascripts
+ \==================================================
+ / Placed at the end of the document so the pages load faster
+ = javascript_include_tag "application"
+ = yield(:javascript)
diff --git a/app/views/layouts/_main_tabnav.html.erb b/app/views/layouts/_main_tabnav.html.erb
deleted file mode 100644
index f2897eef..00000000
--- a/app/views/layouts/_main_tabnav.html.erb
+++ /dev/null
@@ -1,80 +0,0 @@
-<%
- u = @current_user
- tabs = [
- { :name => "Start", :url => root_path, :active => ["index", "home"],
- :subnav => [
- { :name => "Meine Aufgaben", :url => user_tasks_path },
- { :name => "Meine Bestellgruppe", :url => my_ordergroup_path, :access_denied? => (!u.ordergroup)},
- { :name => "Mein Profil", :url => my_profile_path}
- ]
- },
- { :name => "Foodcoop", :url => tasks_path,
- :active => ["foodcoop", "tasks", "messages", "foodcoop/ordergroups", "foodcoop/workgroups", "foodcoop/users"],
- :subnav => [
- { :name => "Mitglieder", :url => foodcoop_users_path},
- { :name => "Abeitsgruppen", :url => foodcoop_workgroups_path},
- { :name => "Bestellgruppen", :url => foodcoop_ordergroups_path},
- { :name => "Nachrichten", :url => messages_path},
- { :name => "Aufgaben", :url => tasks_path}
- ]
- },
- { :name => "Wiki", :url => wiki_path, :active => ["pages", "wiki"],
- :subnav => [
- { :name => "Startseite", :url => wiki_path },
- { :name => "Alle Seiten", :url => all_pages_path }
- ]
- },
- { :name => "Bestellungen", :url => u.ordergroup ? ordering_path : orders_path,
- :active => ["orders", "ordering"],
- :subnav => [
- { :name => "Bestellen!", :url => ordering_path },
- { :name => "Meine Bestellungen", :url => my_orders_path },
- { :name => "Bestellverwaltung", :url => orders_path, :access_denied? => (!u.role_orders?) }
- ]
- },
- { :name => "Artikel", :url => suppliers_path,
- :active => ["articles", "suppliers", "deliveries", "article_categories", "stockit", "stock_takings"],
- :access_denied? => (!u.role_article_meta? && !u.role_suppliers?),
- :subnav => [
- { :name => "Artikel", :url => suppliers_path },
- { :name => "Lager", :url => stock_articles_path },
- { :name => "Lieferantinnen", :url => suppliers_path, :access_denied? => (!u.role_suppliers?) },
- { :name => "Kategorien", :url => article_categories_path }
- ]
- },
- { :name => "Finanzen", :url => finance_root_path,
- :active => ["finance/invoices", "finance/transactions", "finance/balancing"],
- :access_denied? => (!u.role_finance?),
- :subnav => [
- { :name => "Konten verwalten", :url => finance_transactions_path },
- { :name => "Bestellungen abrechnen", :url => finance_balancing_path },
- { :name => "Rechnungen", :url => finance_invoices_path }
- ]
- },
- { :name => "Administration", :url => admin_root_path,
- :active => ["admin/"],
- :access_denied? => (!u.role_admin?),
- :subnav => [
- { :name => "Benutzerinnen", :url => admin_users_path },
- { :name => "Bestellgruppen", :url => admin_ordergroups_path },
- { :name => "Arbeitsgruppen", :url => admin_workgroups_path }
- ]
- }
- ]
--%>
-
- <% for tab in tabs -%>
- <% unless tab[:access_denied?] -%>
-
- <%= link_to tab[:name], tab[:url] %>
-
- <% for subtab in tab[:subnav] -%>
- <% unless subtab[:access_denied?] -%>
- <%= link_to subtab[:name], subtab[:url] %>
- <% end -%>
- <% end -%>
-
-
- <% end -%>
- <% end -%>
-
diff --git a/app/views/layouts/application.haml b/app/views/layouts/application.haml
deleted file mode 100644
index fc8b52b0..00000000
--- a/app/views/layouts/application.haml
+++ /dev/null
@@ -1,38 +0,0 @@
-!!!
-%html
- %head
- %meta{"http-equiv" => "content-type", :content => "text/html;charset=UTF-8"}
- %title= "FoodSoft - " + (yield(:title) or controller.controller_name)
- = stylesheet_link_tag 'main', 'rails_messages', 'nav', :cache => "all_cached"
- = stylesheet_link_tag "print", :media => "print"
-
- = javascript_include_tag 'prototype', 'effects', 'controls', 'application', 'ordering', :cache => "all_cached"
- = yield(:head)
- %body
- #logininfo= render :partial => 'shared/loginInfo'
-
- #header
- #logo
- - link_to root_path do
- food soft
- %span{:style => "color:white; font-size:45%; letter-spacing: -1px;"}= Foodsoft.config[:name]
- #nav= render :partial => 'layouts/main_tabnav'
-
- #main
- #content
- - if flash[:notice]
- %h3.notice#flashNotice= flash[:notice]
- - if flash[:error]
- %h3.error#flashError= flash[:error]
- #loader{:style => "display:none;"}= image_tag("loader.gif", :border => 0)
- - if show_title?
- %h1= yield(:title)
- = yield
- #ajax_box(style="display:none")
-
- - if flash[:notice]
- = javascript_tag("new Effect.Highlight('flashNotice', {delay:0.8, duration:1});")
- - if flash[:error]
- = javascript_tag("new Effect.Highlight('flashError', {delay:0.8, duration:1});")
diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml
new file mode 100644
index 00000000..2feb4fa3
--- /dev/null
+++ b/app/views/layouts/application.html.haml
@@ -0,0 +1,53 @@
+= render layout: 'layouts/header' do
+ .logo
+ = t('layouts.logo').html_safe
+ %ul.nav.nav-pills.pull-right
+ %li.dropdown
+ %a.dropdown-toggle(data-toggle="dropdown" href="#")
+ = current_user.nick
+ %b.caret
+ %ul.dropdown-menu
+ %li= link_to t('.profile'), my_profile_path
+ %li= link_to t('.ordergroup'), my_ordergroup_path
+ %li= link_to t('.logout'), logout_path
+ %li{class: ('disabled' if FoodsoftConfig.config[:homepage].blank?)}
+ = link_to FoodsoftConfig.config[:name], FoodsoftConfig.config[:homepage]
+ %li= link_to t('.help'), FoodsoftConfig.config[:help_url]
+ %li= link_to t('.feedback.title'), new_feedback_path, title: t('.feedback.desc')
+ .clearfix
+
+ .navbar
+ .navbar-inner
+ .container
+ %a.btn.btn-navbar(data-target=".nav-collapse" data-toggle="collapse")
+ %span.icon-bar
+ %span.icon-bar
+ %span.icon-bar
+ .nav-collapse.collapse
+ = render_navigation expand_all: true, renderer: :bootstrap
+
+ .container-fluid
+ .row-fluid
+ - if content_for?(:sidebar)
+ .span3
+ = yield(:sidebar)
+ .span9
+ = bootstrap_flash
+ - if content_for?(:actionbar)
+ .btn-toolbar.pull-right= yield(:actionbar)
+ - if show_title?
+ .page-header
+ %h1= yield(:title)
+ = yield
+ - else
+ = bootstrap_flash
+ - if content_for?(:actionbar)
+ .btn-toolbar.pull-right= yield(:actionbar)
+ - if show_title?
+ .page-header
+ %h1= yield(:title)
+ = yield
+
+ %footer
+ %p= t '.footer'
+ #modalContainer.modal.hide.fade(tabindex="-1" role="dialog")
diff --git a/app/views/layouts/application1.html.haml b/app/views/layouts/application1.html.haml
new file mode 100644
index 00000000..c52e8003
--- /dev/null
+++ b/app/views/layouts/application1.html.haml
@@ -0,0 +1,32 @@
+!!!
+%html
+ %head
+ %meta{"http-equiv" => "content-type", :content => "text/html;charset=UTF-8"}
+ %title= t '.title', title: (yield(:title) or controller.controller_name)
+ = stylesheet_link_tag 'application'
+ = stylesheet_link_tag "print", :media => "print"
+
+ = javascript_include_tag 'application'
+ = csrf_meta_tags
+ = yield(:head)
+ %body
+ #logininfo= render :partial => 'shared/loginInfo'
+
+ #header
+ #logo
+ = link_to root_path do
+ = t('layouts.logo').html_safe
+ %span{:style => "color:white; font-size:45%; letter-spacing: -1px;"}= FoodsoftConfig[:name]
+ #nav= render :partial => 'layouts/main_tabnav'
+
+ #main
+ #content
+ - flash.each do |name, msg|
+ = content_tag :h3, msg, :id => "flash#{name.to_s.camelize}", :class => "flash #{name}"
+ #loader{:style => "display:none;"}= image_tag("loader.gif", :border => 0)
+ - if show_title?
+ %h1= yield(:title)
+ = yield
+ #ajax_box(style="display:none")
diff --git a/app/views/layouts/email.html.erb b/app/views/layouts/email.html.erb
deleted file mode 100644
index a5aa7eff..00000000
--- a/app/views/layouts/email.html.erb
+++ /dev/null
@@ -1,6 +0,0 @@
-<%= yield %>
-
---
-FoodSoft: <%= url_for(:controller => "home", :action => "index", :only_path => false) %>
-Foodcoop-Homepage: <%= Foodsoft.config[:homepage] %>
-Hilfe/Help: <%= Foodsoft.config[:help_url] %>
diff --git a/app/views/layouts/email.text.haml b/app/views/layouts/email.text.haml
new file mode 100644
index 00000000..3a51130a
--- /dev/null
+++ b/app/views/layouts/email.text.haml
@@ -0,0 +1,3 @@
+= yield
+\
+= t '.footer', foodsoft: root_url, foodcoop: FoodsoftConfig[:homepage], help: FoodsoftConfig[:help_url]
diff --git a/app/views/layouts/login.haml b/app/views/layouts/login.haml
deleted file mode 100644
index 1e1d771a..00000000
--- a/app/views/layouts/login.haml
+++ /dev/null
@@ -1,16 +0,0 @@
-!!!
-%html
- %head
- %meta{"http-equiv" => "content-type", :content => "text/html;charset=UTF-8"}
- %title= "FoodSoft - " + (yield(:title) or controller.controller_name)
- = stylesheet_link_tag 'main', 'rails_messages', 'nav', :cache => "all_cached"
- = javascript_include_tag 'prototype', 'effects', 'controls', 'application', 'ordering', :cache => "all_cached"
- = yield(:head)
- %body
- #login
- - if yield(:title)
- %h1= yield(:title)
- = yield
- #meta
- Foodcoop
- = link_to_if Foodsoft.config[:homepage], Foodsoft.config[:name], Foodsoft.config[:homepage]
diff --git a/app/views/layouts/login.html.haml b/app/views/layouts/login.html.haml
new file mode 100644
index 00000000..486149f7
--- /dev/null
+++ b/app/views/layouts/login.html.haml
@@ -0,0 +1,12 @@
+= render layout: 'layouts/header' do
+ .container
+ .row
+ .span6.offset3
+ = bootstrap_flash
+ - if show_title?
+ .page-header
+ %h1= yield(:title)
+ = yield
+
+ %footer
+ %p= t '.footer'
diff --git a/app/views/login/accept_invitation.html.haml b/app/views/login/accept_invitation.html.haml
new file mode 100644
index 00000000..07489ebc
--- /dev/null
+++ b/app/views/login/accept_invitation.html.haml
@@ -0,0 +1,11 @@
+- content_for :javascript do
+ :javascript
+ $('user_nick').focus();
+
+- title t('.title', name: FoodsoftConfig[:name])
+= t('.body', group: h(@invite.group.name), foodcoop: h(FoodsoftConfig[:name])).html_safe
+= simple_form_for @user, url: accept_invitation_path do |form|
+ = render partial: 'shared/user_form_fields', locals: {f: form}
+ .form-actions
+ = submit_tag t('.submit'), class: 'btn'
+
diff --git a/app/views/login/forgot_password.html.haml b/app/views/login/forgot_password.html.haml
index 0578df73..568ac258 100644
--- a/app/views/login/forgot_password.html.haml
+++ b/app/views/login/forgot_password.html.haml
@@ -1,18 +1,7 @@
-- title "Passwort vergessen?"
-- if flash[:error]
- %p{:style => "color: red"}= flash[:error]
-%p
- Kein Problem, Du kannst dir einfach ein neues Passwort zulegen.
-%p
- Dazu musst hier die E-Mail-Adresse eingeben, mit der Du in der FoodSoft angemeldet bist.
- Du erhälst dann eine E-Mail mit weiteren Instruktionen.
-
-.edit_form{:style => "width:25em"}
- - form_tag(:action => 'reset_password') do
- %p
- E-Mail:
- %br/
- = text_field 'login', 'email'
- = submit_tag 'Neues Passwort anfordern'
- |
- = link_to 'Abbrechen', login_path
+- title t('.title')
+= t('.body').html_safe
+= simple_form_for User.new, url: {action: 'reset_password'} do |form|
+ = form.input :email
+ .form-actions
+ = form.submit t('.submit'), class: 'btn'
+ = link_to t('ui.or_cancel'), :back
diff --git a/app/views/login/invite.haml b/app/views/login/invite.haml
deleted file mode 100644
index 34cebb67..00000000
--- a/app/views/login/invite.haml
+++ /dev/null
@@ -1,52 +0,0 @@
-- title "Einladung in die #{Foodsoft.config[:name]}"
-%p
- Du bist eingeladen worden als Mitglied der Gruppe
- %b= @invite.group.name
- in der Foodcoop
- = Foodsoft.config[:name]
- mitzumachen.
-%p
- Wenn Du mitmachen möchtest, dann fülle bitte dieses Formular aus.
-%p
- Deine Daten werden selbstverständlich nicht an Dritte, aus was auch immer für
- Gründen, weitergeben. Du kannst auch entscheiden, wieviel deiner persönlichen
- Daten für alle einsehbar sein sollen. 'Alle' bedeutet hier alle Foodcoop-Mitglieder.
- Die Administratoren haben aber jederzeit Zugriff auf deine Daten.
-.edit_form{:style => "width:25em"}
- - form_for @user, :url => {:action => 'invite'} do |form|
- - if flash[:error]
- %p= flash[:error]
- = form.error_messages
- %p
- Benutzerinnenname (für das Anmelden in der Foodsoft)
- %br/
- = form.text_field :nick, :maxlength => 25
- %p
- Vorname
- %br/
- = form.text_field :first_name, :maxlength => 50, :size => 25
- %p
- Nachname
- %br/
- = form.text_field :last_name
- %p
- Telefon
- %br/
- = form.text_field :phone
- %p
- Passwort
- %br/
- = form.password_field :password
- %p
- bitte Passwort wiederholen
- %br/
- = form.password_field :password_confirmation
-
- %h3 Einstellungen
- - for setting in User::setting_keys.keys
- %p
- = check_box_tag "user[setting_attributes][#{setting}]", '1', @user.settings[setting] == '1' || @user.settings_default(setting)
- %label{:for => "user[setting_attributes][#{setting}]"}= User::setting_keys[setting]
-
- = submit_tag "Absenden"
-= javascript_tag("$('user_nick').focus()")
\ No newline at end of file
diff --git a/app/views/login/login.haml b/app/views/login/login.haml
deleted file mode 100644
index a57cee72..00000000
--- a/app/views/login/login.haml
+++ /dev/null
@@ -1,33 +0,0 @@
-- content_for :head do
- :javascript
- document.observe("dom:loaded", function() {
- // initially hide javascript warn message, when javascript is available
- $('javascript-warn').hide(); $('login-form').show();
-
- $('login_user').focus();
- });
-
-- title "FoodSoft login"
-
-#javascript-warn.error(style="font-size:1.5em")
- %b Achtung, Cookies und Javascript müssen aktiviert sein!
- = link_to "NoScript", "http://noscript.net/"
- bitte abschalten.
-
-#login-form.edit_form(style="width:25em;display:none")
- - form_tag :action => 'login' do
- - if flash[:notice]
- %div.notice= flash[:notice]
- - if flash[:error]
- %div.error= flash[:error]
- %p
- %label{:for => 'user'} Benutzerin
- %br/
- = text_field 'login', 'user'
- %p
- %label{:for => 'password'} Passwort
- %br/
- = password_field 'login', 'password'
- = submit_tag "Anmelden"
- |
- = link_to "Passwort vergessen?", :action => 'forgot_password'
\ No newline at end of file
diff --git a/app/views/login/new_password.html.haml b/app/views/login/new_password.html.haml
new file mode 100644
index 00000000..d3f2c58c
--- /dev/null
+++ b/app/views/login/new_password.html.haml
@@ -0,0 +1,7 @@
+- title t('.title')
+= t('.body', user: h(@user.nick)).html_safe
+= simple_form_for @user, :url => {:action => 'update_password', :id => @user.id, :token => @user.reset_password_token} do |form|
+ = form.input :password
+ = form.input :password_confirmation
+ .form-actions
+ = form.submit t('.submit'), class: 'btn'
diff --git a/app/views/login/password.html.haml b/app/views/login/password.html.haml
deleted file mode 100644
index b83e435a..00000000
--- a/app/views/login/password.html.haml
+++ /dev/null
@@ -1,16 +0,0 @@
-- title "Neues Passwort"
-%p=h "Bitte neues Passwort für #{@user.nick} eingeben."
-.edit_form{:style => "width:25em"}
- - form_for @user, :url => {:action => 'update_password', :id => @user.id, :token => @user.reset_password_token} do |form|
- = form.error_messages :header_message => ""
- %p
- Neues Passwort
- %br/
- = form.password_field :password
- %p
- Passwort wiederholen
- %br/
- = form.password_field :password_confirmation
- = form.submit 'Speichern'
- |
- = link_to 'Abbrechen', login_path
diff --git a/app/views/mailer/feedback.erb b/app/views/mailer/feedback.erb
deleted file mode 100644
index 97cc7b85..00000000
--- a/app/views/mailer/feedback.erb
+++ /dev/null
@@ -1,3 +0,0 @@
-<%= @user.nick %> schrieb am <%= I18n.l Time.now, :format => :short %>:
-
-<%= @message %>
diff --git a/app/views/mailer/feedback.text.haml b/app/views/mailer/feedback.text.haml
new file mode 100644
index 00000000..7708e297
--- /dev/null
+++ b/app/views/mailer/feedback.text.haml
@@ -0,0 +1,3 @@
+= t '.header', user: @user.nick, date: I18n.l(Time.now, :format => :short)
+\
+= @feedback
diff --git a/app/views/mailer/foodsoft_message.text.haml b/app/views/mailer/foodsoft_message.text.haml
new file mode 100644
index 00000000..fd189ea5
--- /dev/null
+++ b/app/views/mailer/foodsoft_message.text.haml
@@ -0,0 +1,4 @@
+= @message.body
+======================================================================
+\
+= t '.footer', reply_url: new_message_url('message[reply_to]' => @message.id), msg_url: message_url(@message), profile_url: my_profile_url
diff --git a/app/views/mailer/invite.html.erb b/app/views/mailer/invite.html.erb
deleted file mode 100644
index 25143e9d..00000000
--- a/app/views/mailer/invite.html.erb
+++ /dev/null
@@ -1,17 +0,0 @@
-Hallo!
-
-<%= @invite.user.first_name %> <%= @invite.user.last_name %> (<%= @invite.user.email %>) hat dich in die Gruppe "<%= @invite.group.name %>" eingeladen.
-Um die Einladung anzunehmen und der Foodcoop beizutreten, gehe zu: <%= @link %>
-Dieser Link kann nur einmal aufgerufen werden und ist nur bis <%= @invite.expires_at.strftime('%A den %d.%m.%Y um %H:%M') %> gültig.
-
-Grüße sendet die Foodsoft!
-
-=======
-
-Hi!
-
-<%= @invite.user.first_name %> <%= @invite.user.last_name %> (<%= @invite.user.email %>) has invited you to join the group "<%= @invite.group.name %>".
-To accept the invitation and to join the foodcoop please follow this link: <%= @link %>
-This link works only once and expires on <%= @invite.expires_at.strftime('%A den %d.%m.%Y um %H:%M') %>.
-
-Greetings, your FoodSoft Team!
diff --git a/app/views/mailer/invite.text.haml b/app/views/mailer/invite.text.haml
new file mode 100644
index 00000000..e937b937
--- /dev/null
+++ b/app/views/mailer/invite.text.haml
@@ -0,0 +1,6 @@
+= t '.text', user: @invite.user.name, mail: @invite.user.email, group: @invite.group.name, link: @link, expires: I18n.l(@invite.expires_at)
+-# append english text only if the locale is not english
+- if not I18n.locale.to_s.start_with?('en')
+ =======
+ \
+ = t '.text', user: @invite.user.name, mail: @invite.user.email, group: @invite.group.name, link: @link, expires: I18n.l(@invite.expires_at, locale: :en), locale: :en
diff --git a/app/views/mailer/message.rhtml b/app/views/mailer/message.rhtml
deleted file mode 100644
index 4824c7f9..00000000
--- a/app/views/mailer/message.rhtml
+++ /dev/null
@@ -1,12 +0,0 @@
-Foodsoft-Nachricht
-
-Von: <%= @sender %>
-An: <%= @recipients %>
-
-======================================================================
-<%= @body %>
-======================================================================
-
-Antworten: <%= @reply %>
-Nachricht online einsehen: <%= @link %>
-Nachrichten-Einstellungen: <%= @profile %>
diff --git a/app/views/mailer/negative_balance.html.erb b/app/views/mailer/negative_balance.html.erb
deleted file mode 100644
index f44aea6e..00000000
--- a/app/views/mailer/negative_balance.html.erb
+++ /dev/null
@@ -1,9 +0,0 @@
-Liebe <%= @group.name %>,
-
-euer Kontostand ist durch eine Buchung am <%= @transaction.created_on.strftime('%d.%m.%Y um %H:%M') %> ins Minus gerutscht: <%= @group.account_balance %>
-
-Es wurden <%= @transaction.amount %> für "<%= @transaction.note %>" abgebucht, die Buchung wurde von <%= @transaction.user.nick %> erstellt.
-
-Bitte zahlt so bald wie möglich wieder Geld ein, um das Gruppenkonto auszugleichen.
-
-Viele Grüße von <%= Foodsoft.config[:name] %>
\ No newline at end of file
diff --git a/app/views/mailer/negative_balance.text.haml b/app/views/mailer/negative_balance.text.haml
new file mode 100644
index 00000000..51d4f6e7
--- /dev/null
+++ b/app/views/mailer/negative_balance.text.haml
@@ -0,0 +1 @@
+= t '.text', group: @group.name, when: @transaction.created_on.strftime('%d.%m.%Y um %H:%M'), balance: @group.account_balance, amount:@transaction.amount, note: @transaction.note, user: @transaction.user.nick, foodcoop: FoodsoftConfig[:name]
diff --git a/app/views/mailer/not_enough_users_assigned.erb b/app/views/mailer/not_enough_users_assigned.erb
deleted file mode 100644
index c85dd912..00000000
--- a/app/views/mailer/not_enough_users_assigned.erb
+++ /dev/null
@@ -1,11 +0,0 @@
-Liebe(r) <%= @user.first_name %>,
-
-Der Job <%= @task.name -%> Deiner Arbeitsgruppe ist am <%= @task.due_date.strftime("%d. %b") -%> fällig
-und es fehlen noch Mitstreiterinnen!
-
-Sofern Du Dich noch nicht für diese Aufgabe eingetragen hast ist das jetzt die Chance:
- <%= @task_url %>
-
---
-Deine Aufgaben: <%= url_for(:controller => "home", :actions => "user") %>
-
diff --git a/app/views/mailer/not_enough_users_assigned.text.haml b/app/views/mailer/not_enough_users_assigned.text.haml
new file mode 100644
index 00000000..763fb411
--- /dev/null
+++ b/app/views/mailer/not_enough_users_assigned.text.haml
@@ -0,0 +1 @@
+= t '.text', user: @user.first_name, task: @task.name, when: I18n.l(@task.due_date, format: t('mailer.dateformat')), workgroup_tasks_url: workgroup_tasks_url(workgroup_id: task.workgroup_id), user_tasks_url: user_tasks_url
diff --git a/app/views/mailer/order_result.html.erb b/app/views/mailer/order_result.html.erb
deleted file mode 100644
index 6381856f..00000000
--- a/app/views/mailer/order_result.html.erb
+++ /dev/null
@@ -1,14 +0,0 @@
-Liebe <%= @group_order.ordergroup.name %>,
-
-die Bestellung für "<%= @order.name %>" wurde am <%= @order.ends.strftime('%d.%m.%Y um %H:%M') %> von <%= @order.updated_by.nick %> beendet.
-
-Für Euch wurden die folgenden Artikel bestellt:
-<% for group_order_article in @group_order.group_order_articles.ordered.all(:include => :order_article)
- article = group_order_article.order_article.article -%>
-<%= article.name %>: <%= group_order_article.result %> x <%= article.unit %> = <%= group_order_article.result * article.fc_price %>
-<% end -%>
-Gesamtpreis: <%= @group_order.price %>
-
-Bestellung online einsehen: <%= url_for(:controller => "ordering", :action => "my_order_result", :id => @order.id) %>
-
-Viele Grüße von <%= Foodsoft.config[:name] %>
\ No newline at end of file
diff --git a/app/views/mailer/order_result.text.haml b/app/views/mailer/order_result.text.haml
new file mode 100644
index 00000000..e797dadc
--- /dev/null
+++ b/app/views/mailer/order_result.text.haml
@@ -0,0 +1,5 @@
+= t '.text0', ordergroup: @group_order.ordergroup.name, order: @order.name, when: I18n.l(@order.ends), user: @order.updated_by.nick
+- for group_order_article in @group_order.group_order_articles.ordered.all(:include => :order_article)
+- article = group_order_article.order_article.article
+ #{article.name}: #{group_order_article.result} x #{article.unit} = #{group_order_article.result * article.fc_price}
+= t '.text1', sum: @group_order.price, order_url: group_order_url(@group_order), foodcoop: FoodsoftConfig[:name]
diff --git a/app/views/mailer/reset_password.html.erb b/app/views/mailer/reset_password.html.erb
deleted file mode 100644
index 6f83c130..00000000
--- a/app/views/mailer/reset_password.html.erb
+++ /dev/null
@@ -1,18 +0,0 @@
-Hallo <%= @user.nick %>,
-
-du (oder jemand anderes) hat auf der FoodSoft-Website ein neues Passwort angefordert.
-Um ein neues Passwort einzugeben, gehe zu: <%= @link %>
-Dieser Link kann nur einmal aufgerufen werden und läuft am <%= @user.reset_password_expires.strftime('%A (%d.%m.%Y %H:%M)') %> ab.
-Wenn du das Passwort nicht ändern möchtest oder diese Email nicht ausgelöst hast, brauchst du nichts zu tun. Dein bisheriges Passwort wurde nicht geändert.
-
-Grüße sendet die Foodsoft! :)
-
-===========
-
-Hi <%= @user.nick %>,
-you have (or someone else has) requested a new password.
-In order to choose a new password follow this link: <%= @link %>
-This link works only once and expires on <%= @user.reset_password_expires.strftime('%A (%d.%m.%Y %H:%M)') %>.
-If you don't want to change your password, just ignore this message. Your password hasn't been changed yet.
-
-Greetings, your FoodSoft Team!
diff --git a/app/views/mailer/reset_password.text.haml b/app/views/mailer/reset_password.text.haml
new file mode 100644
index 00000000..805b32b0
--- /dev/null
+++ b/app/views/mailer/reset_password.text.haml
@@ -0,0 +1 @@
+= t '.text', user: @user.nick, link: @link, expires: I18n.l(@user.reset_password_expires)
diff --git a/app/views/mailer/upcoming_tasks.html.erb b/app/views/mailer/upcoming_tasks.html.erb
deleted file mode 100644
index cadeddf5..00000000
--- a/app/views/mailer/upcoming_tasks.html.erb
+++ /dev/null
@@ -1,16 +0,0 @@
-Liebe(r) <%= @user.name %>,
-
-Du bist für "<%= @task.name -%>" eingetragen. Die Aufgabe ist morgen (<%= @task.due_date.strftime("%d. %b") -%>) fällig!
-
-<% if @user.next_tasks.size > 1 -%>
-Aufgaben für die nächste Woche:
- <% for next_task in @user.next_tasks -%>
- <% unless next_task == @task -%>
-* <%= next_task.due_date.strftime("%d.%m.") -%> <%= next_task.name %>
- <% end -%>
- <% end -%>
-<% end -%>
-
-Meine Aufgaben: <%= url_for(:controller => "home", :actions => "user") %>
-
-Viele Grüße von <%= Foodsoft.config[:name] %>
\ No newline at end of file
diff --git a/app/views/mailer/upcoming_tasks.text.haml b/app/views/mailer/upcoming_tasks.text.haml
new file mode 100644
index 00000000..735aaf52
--- /dev/null
+++ b/app/views/mailer/upcoming_tasks.text.haml
@@ -0,0 +1,7 @@
+= t '.text0', user: @user.name, task: @task.name, when: I18n.l(@task.due_date, format: t('mailer.dateformat'))
+- if @user.next_tasks.size > 0
+ = t '.nextweek'
+ - for next_task in @user.next_tasks
+ - next if next_task == @task
+ * #{I18n.l next_task.due_date, format: t('mailer.dateformat')} #{next_task.name}
+= t '.text1', user_tasks_url: user_tasks_url, foodcoop: FoodsoftConfig[:name]
diff --git a/app/views/messages/_messages.html.haml b/app/views/messages/_messages.html.haml
index b7738161..2874fe7a 100644
--- a/app/views/messages/_messages.html.haml
+++ b/app/views/messages/_messages.html.haml
@@ -1,10 +1,14 @@
-- unless @messages.empty?
- %table.list
+- if pagination
+ - if Message.public.count > 20
+ = items_per_page
+ = pagination_links_remote messages
+
+- unless messages.empty?
+ %table.table.table-striped
%tbody
- - for message in @messages
- %tr{:class => cycle('even','odd', :name => 'messages')}
- %td= format_subject(message, subject_length)
+ - for message in messages
+ %tr
+ %td= format_subject(message, 130)
%td= h(message.sender_name)
%td= format_time(message.created_at)
- %td= link_to('Antworten', reply_message_path(message))
-
\ No newline at end of file
+ %td= link_to t('.reply'), new_message_path(:message => {:reply_to => message.id}), class: 'btn'
diff --git a/app/views/messages/index.html.haml b/app/views/messages/index.html.haml
index 3ce8fa1e..b8c41859 100644
--- a/app/views/messages/index.html.haml
+++ b/app/views/messages/index.html.haml
@@ -1,8 +1,6 @@
-- title "Nachrichten im Überblick"
-
-%p= link_to('Neue Nachricht', :action => 'new')
-
-%div{:style => "text-align:right"}= will_paginate @messages
+- title t('.title')
+- content_for :actionbar do
+ = link_to t('.new'), new_message_path, class: 'btn btn-primary'
#messages
- = render :partial => 'messages', :locals => { :subject_length => 130 }
\ No newline at end of file
+ = render 'messages', messages: @messages, pagination: true
diff --git a/app/views/messages/index.js.haml b/app/views/messages/index.js.haml
new file mode 100644
index 00000000..90dcadd3
--- /dev/null
+++ b/app/views/messages/index.js.haml
@@ -0,0 +1 @@
+$('#messages').html('#{j(render('messages', messages: @messages, pagination: true))}');
\ No newline at end of file
diff --git a/app/views/messages/new.haml b/app/views/messages/new.haml
index ee119d96..8541b996 100644
--- a/app/views/messages/new.haml
+++ b/app/views/messages/new.haml
@@ -1,65 +1,46 @@
-%h1 Neue Nachricht
+- content_for :javascript do
+ :javascript
+ $(function() {
+ $('#message_recipient_tokens').tokenInput("#{users_path(:format => :json)}", {
+ crossDomain: false,
+ prePopulate: $('#message_recipient_tokens').data('pre'),
+ hintText: '#{t '.search_user'}',
+ noResultText: '#{t '.no_user_found'}',
+ searchingText: '#{t '.search'}',
+ theme: 'facebook'
+ });
-- form_for @message do |f|
- = f.error_messages
+ $('#message_sent_to_all').click(function() {
+ if ($(this).is(':checked')) {
+ $('#recipients').slideUp();
+ } else {
+ $('#recipients').slideDown();
+ }
+ });
+ });
- %p
- Empfängerinnen
- %fieldset
- - if Foodsoft.config[:mailing_list].blank?
- = f.check_box :sent_to_all, :onchange => "Element.toggle('recipients')"
- gesamte Foodcoop
+- title t('.title')
+
+= simple_form_for @message do |f|
+ - if FoodsoftConfig[:mailing_list].blank?
+ = f.input :sent_to_all, :as => :boolean
+ - else
+ %b= t '.list.desc', list: mail_to(FoodsoftConfig[:mailing_list])
+ %br/
+ %small{:style => "color:grey"}
+ = t '.list.subscribe_msg'
+ %br/
+ - if FoodsoftConfig[:mailing_list_subscribe].blank?
+ = t '.list.subscribe', link: link_to(t('.list.wiki'), wiki_page_path('MailingListe'))
- else
- %b Nachrichten an alle
- verschickst Du bitte über den Verteiler:
- = mail_to Foodsoft.config[:mailing_list]
- %br/
- %small{:style => "color:grey"}
- Eventuell musst Du Dich dem Verteiler erst bekannt machen.
- %br/
- - if Foodsoft.config[:mailing_list_subscribe].blank?
- Erklärungen zum Verteiler findest Du im
- = link_to 'Wiki (Abschnitt Mailing-Liste)', wiki_page_path('MailingListe')
- - else
- z.b. mit einer Mail an
- = mail_to Foodsoft.config[:mailing_list_subscribe]
- %table#recipients
- %tr
- %td
- %b BenutzerInnen:
- %br/
- %small{:style => "color:grey"} (Mehrere Benutzerinnen mit Komma trennen)
- %br/
- = text_field_with_auto_complete(:message, :recipients_nicks, {:value => @message.recipients_nicks}, {:tokens => ","})
- :javascript
- var userListLoaded = false;
- function checkUserList() {
- if (userListLoaded) {
- $('user-list').toggle();
- }
- return !userListLoaded;
- }
- = link_to_remote('Liste', :update => 'user-list', :url => {:action => 'user_list'}, :complete => 'userListLoaded = true', :condition => 'checkUserList()')
- #user-list.auto_complete
- %tr
- %td
- %b Gruppe:
- %br/
- = f.select :group_id, groups_for_select, :prompt => " -- Gruppe auswählen --"
+ = t '.list.mail', email: mail_to(FoodsoftConfig[:mailing_list_subscribe])
- %p
- Privat
- = f.check_box :private
- %small{:style => "color:grey"} (Nachricht taucht nicht im Foodsoft-Nachrichteneingang auf)
-
- %p
- Betreff
- %br/
- = f.text_field :subject
-
- %p
- Nachricht
- %br/
- ~ f.text_area :body, :cols => '80', :rows => '20'
-
- = submit_tag "Senden"
+ #recipients
+ = f.input :recipient_tokens, :input_html => { 'data-pre' => User.find_all_by_id(@message.recipients_ids).map { |u| u.token_attributes }.to_json }
+ = f.input :group_id, :as => :select, :collection => Group.undeleted.order('type DESC, name ASC').all.reject { |g| g.memberships.empty? }
+ = f.input :private
+ = f.input :subject, input_html: {class: 'input-xxlarge'}
+ = f.input :body, input_html: {class: 'input-xxlarge'}
+ .form-actions
+ = f.submit class: 'btn btn-primary'
+ = link_to t('ui.or_cancel'), :back
diff --git a/app/views/messages/show.haml b/app/views/messages/show.haml
index 322d5247..a1b0c139 100644
--- a/app/views/messages/show.haml
+++ b/app/views/messages/show.haml
@@ -1,21 +1,21 @@
-- title "Nachricht anzeigen"
+- title t('.title')
%div{:style => "width:40em"}
%table{:style => "width:25em"}
%tr
- %td Von:
+ %td= t '.from'
%td=h @message.sender_name
%tr
- %td Betreff:
+ %td= t '.subject'
%td
%b=h @message.subject
%tr
- %td Gesendet:
+ %td= t '.sent_on'
%td= format_time(@message.created_at)
%hr/
%p= simple_format(h(@message.body))
%hr/
%p
- = link_to('Antworten', reply_message_path(@message))
+ = link_to t('.reply'), new_message_path(:message => {:reply_to => @message.id}), class: 'btn'
|
- = link_to 'Nachricht im Überblick', messages_path
\ No newline at end of file
+ = link_to t('.all_messages'), messages_path
diff --git a/app/views/order_comments/_form.html.haml b/app/views/order_comments/_form.html.haml
new file mode 100644
index 00000000..b91b7cc5
--- /dev/null
+++ b/app/views/order_comments/_form.html.haml
@@ -0,0 +1,5 @@
+= simple_form_for order_comment, remote: true, html: {class: 'form-vertical'} do |f|
+ = f.hidden_field :order_id
+ = f.hidden_field :user_id
+ = f.input :text, input_html: {class: 'input-xlarge', rows: '5'}
+ = f.submit class: 'btn'
\ No newline at end of file
diff --git a/app/views/order_comments/create.js.haml b/app/views/order_comments/create.js.haml
new file mode 100644
index 00000000..70b15fe0
--- /dev/null
+++ b/app/views/order_comments/create.js.haml
@@ -0,0 +1 @@
+$('#comments').html('#{escape_javascript(render(:partial => 'shared/comments', :locals => { :comments => @order_comment.order.comments }))}');
diff --git a/app/views/order_comments/new.js.haml b/app/views/order_comments/new.js.haml
new file mode 100644
index 00000000..6d7d03ad
--- /dev/null
+++ b/app/views/order_comments/new.js.haml
@@ -0,0 +1 @@
+$('#new_comment').html('#{escape_javascript(render('form', :locals => { :order_comment => @order_comment}))}');
diff --git a/app/views/ordergroups/edit.html.erb b/app/views/ordergroups/edit.html.erb
deleted file mode 100644
index a7fd7911..00000000
--- a/app/views/ordergroups/edit.html.erb
+++ /dev/null
@@ -1,88 +0,0 @@
-<% title "Edit Ordergroup" %>
-
-<% form_for @ordergroup do |f| %>
- <%= f.error_messages %>
-
- <%= f.label :type %>
- <%= f.text_field :type %>
-
-
- <%= f.label :name %>
- <%= f.text_field :name %>
-
-
- <%= f.label :description %>
- <%= f.text_field :description %>
-
-
- <%= f.label :account_balance %>
- <%= f.text_field :account_balance %>
-
-
- <%= f.label :account_updated %>
- <%= f.datetime_select :account_updated %>
-
-
- <%= f.label :created_on %>
- <%= f.datetime_select :created_on %>
-
-
- <%= f.label :role_admin %>
- <%= f.check_box :role_admin %>
-
-
- <%= f.label :role_suppliers %>
- <%= f.check_box :role_suppliers %>
-
-
- <%= f.label :role_article_meta %>
- <%= f.check_box :role_article_meta %>
-
-
- <%= f.label :role_finance %>
- <%= f.check_box :role_finance %>
-
-
- <%= f.label :role_orders %>
- <%= f.check_box :role_orders %>
-
-
- <%= f.label :weekly_task %>
- <%= f.check_box :weekly_task %>
-
-
- <%= f.label :weekday %>
- <%= f.text_field :weekday %>
-
-
- <%= f.label :task_name %>
- <%= f.text_field :task_name %>
-
-
- <%= f.label :task_description %>
- <%= f.text_field :task_description %>
-
-
- <%= f.label :task_required_users %>
- <%= f.text_field :task_required_users %>
-
-
- <%= f.label :deleted_at %>
- <%= f.datetime_select :deleted_at %>
-
-
- <%= f.label :contact_person %>
- <%= f.text_field :contact_person %>
-
-
- <%= f.label :contact_phone %>
- <%= f.text_field :contact_phone %>
-
-
- <%= f.label :contact_address %>
- <%= f.text_field :contact_address %>
-
- <%= f.submit "Submit" %>
-<% end %>
-
-
diff --git a/app/views/ordergroups/edit.html.haml b/app/views/ordergroups/edit.html.haml
new file mode 100644
index 00000000..3a3eacba
--- /dev/null
+++ b/app/views/ordergroups/edit.html.haml
@@ -0,0 +1,84 @@
+- title t('.title')
+- form_for @ordergroup do |f|
+ = f.error_messages
+ %p
+ = f.label :type
+ %br/
+ = f.text_field :type
+ %p
+ = f.label :name
+ %br/
+ = f.text_field :name
+ %p
+ = f.label :description
+ %br/
+ = f.text_field :description
+ %p
+ = f.label :account_balance
+ %br/
+ = f.text_field :account_balance
+ %p
+ = f.label :account_updated
+ %br/
+ = f.datetime_select :account_updated
+ %p
+ = f.label :created_on
+ %br/
+ = f.datetime_select :created_on
+ %p
+ = f.label :role_admin
+ %br/
+ = f.check_box :role_admin
+ %p
+ = f.label :role_suppliers
+ %br/
+ = f.check_box :role_suppliers
+ %p
+ = f.label :role_article_meta
+ %br/
+ = f.check_box :role_article_meta
+ %p
+ = f.label :role_finance
+ %br/
+ = f.check_box :role_finance
+ %p
+ = f.label :role_orders
+ %br/
+ = f.check_box :role_orders
+ %p
+ = f.label :weekly_task
+ %br/
+ = f.check_box :weekly_task
+ %p
+ = f.label :weekday
+ %br/
+ = f.text_field :weekday
+ %p
+ = f.label :task_name
+ %br/
+ = f.text_field :task_name
+ %p
+ = f.label :task_description
+ %br/
+ = f.text_field :task_description
+ %p
+ = f.label :task_required_users
+ %br/
+ = f.text_field :task_required_users
+ %p
+ = f.label :deleted_at
+ %br/
+ = f.datetime_select :deleted_at
+ %p
+ = f.label :contact_person
+ %br/
+ = f.text_field :contact_person
+ %p
+ = f.label :contact_phone
+ %br/
+ = f.text_field :contact_phone
+ %p
+ = f.label :contact_address
+ %br/
+ = f.text_field :contact_address
+ %p= f.submit t('ui.edit')
diff --git a/app/views/ordergroups/index.html.erb b/app/views/ordergroups/index.html.erb
deleted file mode 100644
index fca03433..00000000
--- a/app/views/ordergroups/index.html.erb
+++ /dev/null
@@ -1,52 +0,0 @@
-<% title "Ordergroups" %>
-
-
-
- Type
- Name
- Description
- Account Balance
- Account Updated
- Created On
- Role Admin
- Role Suppliers
- Role Article Meta
- Role Finance
- Role Orders
- Weekly Task
- Weekday
- Task Name
- Task Description
- Task Required Users
- Deleted At
- Contact Person
- Contact Phone
- Contact Address
-
- <% for ordergroup in @ordergroups %>
-
- <%=h ordergroup.type %>
- <%=h ordergroup.name %>
- <%=h ordergroup.description %>
- <%=h ordergroup.account_balance %>
- <%=h ordergroup.account_updated %>
- <%=h ordergroup.created_on %>
- <%=h ordergroup.role_admin %>
- <%=h ordergroup.role_suppliers %>
- <%=h ordergroup.role_article_meta %>
- <%=h ordergroup.role_finance %>
- <%=h ordergroup.role_orders %>
- <%=h ordergroup.weekly_task %>
- <%=h ordergroup.weekday %>
- <%=h ordergroup.task_name %>
- <%=h ordergroup.task_description %>
- <%=h ordergroup.task_required_users %>
- <%=h ordergroup.deleted_at %>
- <%=h ordergroup.contact_person %>
- <%=h ordergroup.contact_phone %>
- <%=h ordergroup.contact_address %>
- <%= link_to "Edit", edit_ordergroup_path(ordergroup) %>
-
- <% end %>
-
-
diff --git a/app/views/ordergroups/index.html.haml b/app/views/ordergroups/index.html.haml
new file mode 100644
index 00000000..a436cbe1
--- /dev/null
+++ b/app/views/ordergroups/index.html.haml
@@ -0,0 +1,46 @@
+- title t('.title')
+%table
+ %tr
+ %th Type
+ %th Name
+ %th Description
+ %th Account Balance
+ %th Account Updated
+ %th Created On
+ %th Role Admin
+ %th Role Suppliers
+ %th Role Article Meta
+ %th Role Finance
+ %th Role Orders
+ %th Weekly Task
+ %th Weekday
+ %th Task Name
+ %th Task Description
+ %th Task Required Users
+ %th Deleted At
+ %th Contact Person
+ %th Contact Phone
+ %th Contact Address
+ - for ordergroup in @ordergroups
+ %tr
+ %td= h ordergroup.type
+ %td= h ordergroup.name
+ %td= h ordergroup.description
+ %td= h ordergroup.account_balance
+ %td= h ordergroup.account_updated
+ %td= h ordergroup.created_on
+ %td= h ordergroup.role_admin
+ %td= h ordergroup.role_suppliers
+ %td= h ordergroup.role_article_meta
+ %td= h ordergroup.role_finance
+ %td= h ordergroup.role_orders
+ %td= h ordergroup.weekly_task
+ %td= h ordergroup.weekday
+ %td= h ordergroup.task_name
+ %td= h ordergroup.task_description
+ %td= h ordergroup.task_required_users
+ %td= h ordergroup.deleted_at
+ %td= h ordergroup.contact_person
+ %td= h ordergroup.contact_phone
+ %td= h ordergroup.contact_address
+ %td= link_to t('ui.edit'), edit_ordergroup_path(ordergroup)
diff --git a/app/views/ordering/_order_footer.html.erb b/app/views/ordering/_order_footer.html.erb
deleted file mode 100644
index 8997fc8a..00000000
--- a/app/views/ordering/_order_footer.html.erb
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/app/views/ordering/_order_head.haml b/app/views/ordering/_order_head.haml
deleted file mode 100644
index ada44597..00000000
--- a/app/views/ordering/_order_head.haml
+++ /dev/null
@@ -1,51 +0,0 @@
-- title "Bestellen"
-
-.left_column{:style => "width:49em"}
- .box_title
- %h2=h @order.name
- .column_content
- %table
- %tr{:valign => "top"}
- %td{:width => "60%"}
- %p
- %b Lieferantin:
- =h @order.name
- %p
- %b Erstellt von:
- =h link_to_user_message_if_valid(@order.created_by)
- %p
- %b Ende:
- =h format_time(@order.ends)
- - if @group_order && @group_order.updated_by
- %p
- %b Zuletzt bestellt:
- =h @group_order.updated_by.nick if @group_order.updated_by
- = "(#{format_time(@group_order.updated_on)})"
- %p
- %b Verfügbares Guthaben:
- = number_to_currency(@availableFunds)
- %td
- - unless @order.note.empty?
- %p
- %b Notiz:
- = simple_format(@order.note)
- - unless @order.stockit? || @order.supplier.min_order_quantity.blank?
- %p
- %b Mindestellmenge:
- =h @order.supplier.min_order_quantity
- %p
- %b Gesamtbestellmenge bisher:
- = number_to_currency @order.sum
-
-- orders = Order.open.reject{ |order| order == @order }
-- unless orders.empty?
- .right_column{:style => "width:22em"}
- .box_title
- %h2 Anderer Bestellungen
- .column_content
- %table
- - for order in orders
- %tr
- %td
- = link_to_function order.name, "if (confirmSwitchOrder()) (window.location = '#{ url_for(:action => 'order', :id => order) }' )"
- %td= "noch #{time_ago_in_words(order.ends)}" if order.ends
diff --git a/app/views/ordering/_orders.html.haml b/app/views/ordering/_orders.html.haml
deleted file mode 100644
index 82970631..00000000
--- a/app/views/ordering/_orders.html.haml
+++ /dev/null
@@ -1,17 +0,0 @@
-- if pagination
- = pagination_links_remote @closed_orders, :per_page => 10, :update => 'closed_orders'
-%table.list
- %thead
- %tr
- %th Lieferantin
- %th Ende
- %th Summe
- %tbody
- - for order in orders
- - group_order = order.group_order(@ordergroup) # Get GroupOrder if possible
- - order_class = group_order ? "" : "color:grey"
- %tr{:class=> cycle('even', 'odd', :name => 'orders'), :style => order_class}
- %td= link_to order.name, :action => 'my_order_result', :id => order
- %td= format_time(order.ends)
- %td{:class => "currency"}= group_order ? number_to_currency(group_order.price) : "--"
-
\ No newline at end of file
diff --git a/app/views/ordering/index.haml b/app/views/ordering/index.haml
deleted file mode 100644
index 0bbd3203..00000000
--- a/app/views/ordering/index.haml
+++ /dev/null
@@ -1,44 +0,0 @@
-- title "Bestellüberblick"
-
-// Ordergroups Account Balance
-.left_column{:style => "width:26%"}
- .box_title
- %h2=h @ordergroup.name
- .column_content
- %table
- %tr
- %td Kontostand:
- %td{:class => "currency", :style => "width:5em"}= number_to_currency(@ordergroup.account_balance)
- %tr
- %td - laufende Bestellungen:
- %td{:class => "currency"}= number_to_currency(@ordergroup.value_of_open_orders)
- %tr
- %td - nicht abgerechnete Bestellungen:
- %td{:class => "currency"}= number_to_currency(@ordergroup.value_of_finished_orders)
- %tr
- %th verfügbares Guthaben:
- %th{:class => "currency"}= number_to_currency(@ordergroup.get_available_funds)
-
-.right_column{:style => "width:70%"}
- // open orders
- = render :partial => "shared/open_orders"
-
- // finished orders
- - unless Order.finished.empty?
- .box_title
- %h2 Nicht abgerechnete Bestellungen
- .column_content
- = render :partial => "orders", :locals => {:orders => Order.finished_not_closed, :pagination => false}
- - if @ordergroup.value_of_finished_orders > 0
- %p
- Gesamtsumme:
- %b= number_to_currency(@ordergroup.value_of_finished_orders)
-
- // closed orders
- - unless Order.closed.empty?
- .box_title
- %h2 Abgerechnete Bestellungen
- .column_content
- = render :partial => "orders", :locals => {:orders => Order.closed.all(:limit => 5), :pagination => false}
- %br/
- = link_to "mehr...", :action => "myOrders"
\ No newline at end of file
diff --git a/app/views/ordering/myOrders.haml b/app/views/ordering/myOrders.haml
deleted file mode 100644
index 72f97c11..00000000
--- a/app/views/ordering/myOrders.haml
+++ /dev/null
@@ -1,17 +0,0 @@
-- title "Bestellungen der #{@ordergroup.name}"
-%p
- Siehe hier alle
- = link_to "laufenden Bestellungen.", :action => "index"
-
-.single_column{:style => "width:50em"}
- .box_title
- %h2 beendet/nicht abgerechnet
- .column_content
- = render :partial => "orders", :locals => {:orders => Order.finished_not_closed, :pagination => false}
-
-.single_column{:style => "width:50em"}
- .box_title
- %h2 abgerechnet
- .column_content
- #closed_orders
- = render :partial => "orders", :locals => {:orders => @closed_orders, :pagination => true}
diff --git a/app/views/ordering/my_order_result.haml b/app/views/ordering/my_order_result.haml
deleted file mode 100644
index 2177d73c..00000000
--- a/app/views/ordering/my_order_result.haml
+++ /dev/null
@@ -1,153 +0,0 @@
-- content_for :head do
- :javascript
- document.observe("dom:loaded", function() {
- // initially hide all ignored articles
- $$('tr.ignored').invoke('hide');
- });
- function toggleIgnoredArticles() {
- $$('tr.ignored').invoke('toggle');
- };
-
-
-- title "Dein Bestellergebnis für #{@order.name}"
-#element_navigation
- = link_to_unless @order.previous == @order, "<< #{@order.previous.name}", :action => "my_order_result", :id => @order.previous
- |
- = link_to "Übersicht", :controller => 'ordering'
- |
- = link_to_unless @order.next == @order, "#{@order.next.name} >>", :action => "my_order_result", :id => @order.next
-
-// Order summary
-.left_column{:style => "width:45em"}
- .box_title
- %h2 Zusammenfassung
- .column_content
- %table
- %tr{:valign => "top"}
- %td{:style => "width:50%"}
- %p
- Lieferantin:
- %b=h @order.name
- - unless @order.note.blank?
- %p
- Notiz:
- =h @order.note
- %p
- Erstellt von:
- =h link_to_user_message_if_valid(@order.created_by)
- %p
- Ende:
- %b=h format_time(@order.ends)
- %p
- Bestellsumme:
- - if @group_order
- %b=h number_to_currency(@group_order.price)
- - else
- %b Du hast nicht bestellt.
- - if @order.closed?
- %p
- = "Abgerechnet von #{@order.updated_by.nick}"
- = link_to "Kommentare lesen/schreiben", "#comments"
-
-// directly switch to active orders
-.right_column{:style => "width:23em;"}
- .box_title
- %h2 Laufende Bestellungen
- .column_content
- %table
- - for order in Order.open
- %tr
- %td= link_to order.name, :action => 'order', :id => order
- %td= "("+ time_ago_in_words(order.ends) + ")" if order.ends
-
-// Article box
-.single_column{:style => "clear:both; width:70em;"}
- .box_title
- %h2 Artikelübersicht
- .column_content#result
- - if @group_order
- %p(style="float:right")= link_to_function "Zeige/Verstecke nicht bestellte Artikel", "toggleIgnoredArticles();"
- %p= link_to("Bestellung ändern", :action => "order", :id => @order) if @order.open?
- %table.list
- %thead
- %tr
- %th{:style => "width:40%"} Name
- %th Gebinde
- %th Einzelpreis
- %th
- %abbr{:title => "Menge + Toleranz"} Bestellt
- %th
- %abbr{:title => "Unter Berücksichtigung der derzeitigen Bestellungen aller Gruppen"}
- - if @order.open?
- Zu
- Erhalten
- %th Gesamtpreis
- %tbody
- - total = 0 #set counter for order-sum
- - for category_name, order_articles in @order.articles_grouped_by_category
- %tr{:style => "background-color:#EFEFEF"}
- %td{:style => "text-align:left;"}=h category_name
- %td{:colspan => "9"}
- - for oa in order_articles
- - # get the order-results for the ordergroup
- - goa = oa.group_order_articles.first :conditions => {:group_order_id => @group_order.id}
- - if goa
- - quantity = goa.quantity
- - tolerance = goa.tolerance
- - result = goa.result
- - if @order.open?
- - if Foodsoft.config[:tolerance_is_costly]
- - sub_total = oa.price.fc_price * (quantity + tolerance)
- - else
- - sub_total = oa.price.fc_price * quantity
- - else
- - sub_total = oa.price.fc_price * result
- - else
- - quantity, tolerance, result, sub_total = 0, 0, 0, 0
- - total += sub_total
- - # give the article different colors, dependent on order-result
- - class_name = "ignored"
- - if (quantity + tolerance > 0)
- - class_name = result > 0 ? 'success' : 'failed'
- %tr{:class => cycle('even', 'odd', :name => 'articles') + " " + class_name}
- %td{:style => "width:40%"}
- =h oa.article.name
- - unless oa.article.note.blank?
- = image_tag("lamp_grey.png", {:alt => "Notiz anzeigen", :size => "15x16", :border => "0", :onmouseover => "$('note_#{oa.id}').show();", :onmouseout => "$('note_#{oa.id}').hide();"})
- %td= "#{oa.price.unit_quantity} x #{oa.article.unit}"
- %td= number_to_currency(oa.price.fc_price)
- %td
- = quantity
- = "+ #{tolerance}" if oa.price.unit_quantity > 1
- %td= result > 0 ? result : "0"
- %td= number_to_currency(sub_total)
- - unless oa.article.note.blank?
- %tr{:id => "note_#{oa.id}", :class => "note even", :style => "display:none"}
- %td{:colspan => "6"}=h oa.article.note
- %tr{:class => cycle('even', 'odd', :name => 'articles')}
- %th{:colspan => "5"} Summe
- %th= number_to_currency(total)
- %br/
- = link_to_top
- - else
- - if @order.open?
- Du hast noch nicht bestellt.
- = link_to "Das ist Deine Chance!", :action => "order", :id => @order
- - else
- Die Bestellung is leider schon zu Ende. Beim nächsten mal früher aufstehen...
-
-// Comments box
-.single_column{:style => "width:70em;"}
- .box_title
- %h2 Kommentare
- .column_content#comments
- = render :partial => 'shared/comments', :locals => { :comments => @order.comments }
- %p
- - form_for :comment, :url => { :action => :add_comment, :id => @order } do |form|
- %p
- %b Neuen Kommentar hinzufügen:
- %br/
- = form.text_area :text, :cols => 50, :rows => 6
- %br/
- = submit_tag "Kommentar hinzufügen"
- = link_to_top
diff --git a/app/views/ordering/order.rhtml b/app/views/ordering/order.rhtml
deleted file mode 100644
index aba5d960..00000000
--- a/app/views/ordering/order.rhtml
+++ /dev/null
@@ -1,131 +0,0 @@
-<%= render :partial => 'order_head' %>
-
-<% form_tag(:action => 'saveOrder', :id => @order) do %>
-
-
-
Artikel
-
-
-
-
-
- Name
-
- Preis
- Einheit
- Fehlende Einheiten
- Menge
- <% if not @order.stockit? -%>
- Toleranz
- <% end %>
- Summe
-
-
-
- <%-
- total = 0
- i = 0
- @articles_grouped_by_category.each do |category, order_articles|
- -%>
-
- <%=h category %>
-
-
- <%-
- order_articles.each do |order_article|
- if Foodsoft.config[:tolerance_is_costly]
- article_total = @price[i] * (@tolerance[i] + @quantity[i])
- else
- article_total = @price[i] * @quantity[i]
- end
- total += article_total
- -%>
-
- <%= order_article.article.name %>
- <%=h order_article.article.origin %>
- <%= number_to_currency(@price[i]) %>
- <%= order_article.article.unit %>
-
-
- <%= if @order.stockit?
- order_article.article.quantity_available
- else
- missing_units = @unit[i] - (((@quantity[i] + @others_quantity[i]) % @unit[i]) + @tolerance[i] + @others_tolerance[i])
- missing_units < 0 ? 0 : missing_units
- end %>
-
-
-
- " value="<%= @quantity[i] %>" size="2" />
- <%= @used_quantity[i] %> +
- <%= @quantity[i] - @used_quantity[i] %>
- <%= button_to_function('+', "increaseQuantity(#{i})") %>
- <%= button_to_function('-', "decreaseQuantity(#{i})") %>
-
- <% if not @order.stockit? -%>
-
- " value="<%= @tolerance[i] %>" size="2" />
- <% if (@unit[i] > 1) -%>
- <%= @used_tolerance[i] %> +
- <%= @tolerance[i] - @used_tolerance[i] %>
- <%= button_to_function('+', "increaseTolerance(#{i})") %>
- <%= button_to_function('-', "decreaseTolerance(#{i})") %>
- <% end -%>
-
- <% end %>
- <%= number_to_currency(article_total, :unit => "") %> €
-
-
<%= order_article.article.name -%>
-
- Volle Gebinde: <%= order_article.units_to_order %>
- Gesamt-Einheiten: <%= @quantity[i] + @others_quantity[i] %>
- Gesamt-Toleranz: <%= @tolerance[i] + @others_tolerance[i] %>
-
-
- Hersteller: <%= order_article.article.manufacturer -%>
- Gebinde: <%= @order.stockit? ? order_article.article.quantity_available : @unit[i] %> * <%=h order_article.article.unit %>
- Notiz: <%= order_article.article.note -%>
-
-
-
-
-
- <%- i = i + 1
- end
- end -%>
-
-
-
-
- <%= render "order_footer", :total => total %>
-<% end %>
-
-
\ No newline at end of file
diff --git a/app/views/ordering/stock_order.html.haml b/app/views/ordering/stock_order.html.haml
deleted file mode 100644
index 4f70b45b..00000000
--- a/app/views/ordering/stock_order.html.haml
+++ /dev/null
@@ -1,75 +0,0 @@
-= render :partial => 'order_head'
-
-.single_column{:style => 'clear:both;margin-bottom:7em;'}
- - form_tag(:action => 'saveOrder', :id => @order) do
- .box_title
- %h2 Anderer Bestellungen
- .column_content
- %table#order.list
- %thead
- %tr
- %th Name
- %th
- %th Lieferantin
- %th{:style => "width:5em;"} Einheit
- %th{:style => "width:4.5em;"} Preis
- %th(style="width:20px") Verfügbar
- %th#col_required(style="width:110px") Menge
- %th Summe
- %tbody
- - total = 0
- - i = 0
- - for category_name, order_articles in @articles_grouped_by_category
- %tr{:style => "background-color:#EFEFEF"}
- %td{:style => "text-align:left"}
- %b=h category_name
- %td{:colspan => "9"}
- - for order_article in order_articles
- - article_total = @price[i] * @quantity[i]
- - total += article_total
- %tr{:class => cycle('even', 'odd', :name => 'articles')+' order-article', :valign => "top"}
- %td.name= order_article.article.name
- %td=h order_article.article.origin
- %td=h truncate order_article.article.supplier.name, :length => 11
- %td=h order_article.article.unit
- %td= number_to_currency @price[i]
- %td= @quantity_available[i]
- %td{:style => "text-align:right;"}
- = hidden_field_tag "ordered[#{order_article.id}][quantity]", @quantity[i], :id => "q_#{i}", :size => "2"
- %span.used{:id => "q_used_#{i}"}= @used_quantity[i]
- = button_to_function('+', "increaseStockQuantity(#{i})")
- = button_to_function('-', "decreaseStockQuantity(#{i})")
-
- %td{:id => "td_price_#{i}", :style => "text-align:right; padding-right:10px; width:4em"}
- %span{:id => "price_#{i}_display"}= number_to_currency(article_total, :unit => "")
- €
- .article-info
- %h3= order_article.article.name
- .right
- Gesamt-Einheiten:
- %span{:id => "q_total_#{i}"}= @quantity[i] + @others_quantity[i]
- %br/
- .left
- Hersteller:
- = order_article.article.manufacturer
- %br/
- Gebinde:
- = order_article.article.quantity_available
- *
- = order_article.article.unit
- %br/
- Notiz:
- = order_article.article.note
- %br/
- - i = i + 1
- = render "order_footer", :total => total
-
-%script{:type => "text/" + "javascript"}
- // preset data
- - for i in 0...@price.size
- = "addData(#{@price[i]}, 1, #{@price[i] * @quantity[i]}, #{@others_quantity[i]}, 0, #{@used_quantity[i]}, #{@quantity_available[i]});"
- = "setGroupBalance(#{@availableFunds});"
- // localization
- setDecimalSeparator(",");
- // initialize javascript
- updateBalance();
diff --git a/app/views/orders/_articles.html.haml b/app/views/orders/_articles.html.haml
index 546d088f..3f176128 100644
--- a/app/views/orders/_articles.html.haml
+++ b/app/views/orders/_articles.html.haml
@@ -1,35 +1,39 @@
-%table
- %tr
- %th Name
- %th Gebinde
- %th Netto-/Bruttopreis
- %th Bestellte Einheiten
- - unless order.stockit?
- %th Volle Gebinde
- - total_net, total_gross, counter = 0, 0, 0
- - order.articles_grouped_by_category.each do |category_name, order_articles|
- %tr{:style => "background-color:#EFEFEF"}
- %td{:style => "text-align:left; color: grey;"}=h category_name
- %td{:colspan => "9"}
- - order_articles.each do |order_article|
- - net_price = order_article.price.price
- - gross_price = order_article.price.gross_price
- - units = order_article.units_to_order
- - unit_quantity = order_article.price.unit_quantity
- - total_net += units * unit_quantity * net_price
- - total_gross += units * unit_quantity * gross_price
- %tr{:class => cycle('even', 'odd', :name => 'articles'), :style => "color: #{units > 0 ? 'green' : 'red'}"}
- %td=h order_article.article.name
- %td= "#{unit_quantity} x #{order_article.article.unit}"
- %td= "#{number_to_currency(net_price)} / #{number_to_currency(gross_price)}"
- - if order.stockit?
- %td= units
- - else
- %td= "#{order_article.quantity} + #{order_article.tolerance}" if unit_quantity > 1
- %td= units
+%table.table.table-hover
+ %thead
+ %tr
+ %th= t '.name'
+ %th= t '.unit_quantity'
+ %th= t '.prices'
+ %th= t '.units_ordered'
+ - unless order.stockit?
+ %th= t '.units_full'
+ - total_net, total_gross, counter = 0, 0, 0
+ %tbody
+ - order.articles_grouped_by_category.each do |category_name, order_articles|
+ %tr.article-category
+ %td
+ = category_name
+ %i.icon-tag
+ %td{:colspan => "9"}
+ - order_articles.each do |order_article|
+ - net_price = order_article.price.price
+ - gross_price = order_article.price.gross_price
+ - units = order_article.units_to_order
+ - unit_quantity = order_article.price.unit_quantity
+ - total_net += units * unit_quantity * net_price
+ - total_gross += units * unit_quantity * gross_price
+ %tr{:class => cycle('even', 'odd', :name => 'articles'), :style => "color: #{units > 0 ? 'green' : 'red'}"}
+ %td=h order_article.article.name
+ %td= "#{unit_quantity} x #{order_article.article.unit}"
+ %td= "#{number_to_currency(net_price)} / #{number_to_currency(gross_price)}"
+ - if order.stockit?
+ %td= units
+ - else
+ %td= "#{order_article.quantity} + #{order_article.tolerance}" if unit_quantity > 1
+ %td= units
%p
- Summe (Netto/Brutto-Preise):
+ = t '.prices_sum'
= "#{number_to_currency(total_net)} / #{number_to_currency(total_gross)}"
%p
- Bestellte Artikel.
- = order.order_articles.ordered.count
\ No newline at end of file
+ = t '.article_count'
+ = order.order_articles.ordered.count
diff --git a/app/views/orders/_form.html.haml b/app/views/orders/_form.html.haml
index c5ba0856..78cd3ca8 100644
--- a/app/views/orders/_form.html.haml
+++ b/app/views/orders/_form.html.haml
@@ -1,73 +1,54 @@
-= form.error_messages
+= simple_form_for @order do |f|
+ = f.hidden_field :supplier_id
+ = f.input :note, input_html: {rows: 8}
+ = f.input :starts, input_html: {class: 'input-small'}
+ = f.input :ends, input_html: {class: 'input-small'}
-.single_column
- .box_title
- %h2 Bestellung
- .column_content
- = form.hidden_field :supplier_id
- %p
- Lieferantin:
- = @order.name
- %p
- Notiz
- %br/
- = form.text_area :note, :cols => 50, :rows => 5
- %p
- Start
- %br/
- = form.datetime_select :starts, :start_year => Time.now.year - 1
- %p
- Ende
- %br/
- = form.datetime_select :ends, :start_year => Time.now.year - 1, :include_blank => true
+ %h2= t '.title'
+ - if @order.errors.has_key?(:articles)
+ .alert.alert-error
+ = @order.errors.get(:articles).join(" ")
+ %table.table.table-hover#articleList
+ %tr
+ %th= check_box_tag 'checkall', "1", false, { 'data-check-all' => '#articleList' }
+ %th= t '.name'
+ %th= t '.note'
+ - if @order.stockit?
+ %th= t '.stockit'
+ - else
+ %th= t '.origin'
+ %th= t '.supplier'
+ %th= t '.unit_quantity'
+ %th= t '.prices'
+ - for category_name, articles in @order.articles_for_ordering
+ %tr.article-category
+ %td
+ %td{:colspan => "6", :style => "text-align:left"}
+ = category_name
+ %i.icon-tag
+ - for article in articles
+ / check if the article is selected
+ - included = @order.article_ids.include?(article.id)
+ - included_class = included ? ' selected' : ''
+ %tr{:class => included_class, :id => article.id.to_s }
+ %td= check_box_tag "order[article_ids][]", article.id, included, :id => "checkbox_#{article.id}"
+ %td.click-me{'data-check-this' => "#checkbox_#{article.id}"}= article.name
+ %td=h truncate article.note, :length => 25
+ - if @order.stockit?
+ %td= "#{article.quantity_available} * #{article.unit}"
+ - else
+ %td=h truncate article.origin, :length => 15
+ %td=h truncate article.manufacturer, :length => 15
+ %td= "#{article.unit_quantity} x #{article.unit}"
+ %td= "#{number_to_currency(article.price)} / #{number_to_currency(article.fc_price)}"
+ %tr
+ %td
+ = check_box_tag 'checkall', "1", false, { 'data-check-all' => '#articleList' }
+ %td{:colspan => "6"}= t '.select_all'
- .box_title
- %h2 Artikel
- .column_content
- - if (@template_orders && !@template_orders.empty?)
- %p
- %label{:for => 'template'} Benutze Artikelauswahl von
- %select{:name => "template_id", :onchange => "useTemplate(this[this.selectedIndex].value)"}
- %option{:value => "-1", :selected => "selected"} Bestellung auswählen...
- - i = -1
- - for order in @template_orders
- %option{:value => (i += 1)}= "#{h(order.name)} bis #{order.ends.strftime('%d. %b')}"
- %table.list
- %tr
- %th= check_box_tag 'checkall', "1", false, { :onclick => "checkUncheckAll(this)" }
- %th Name
- %th Notiz
- - if @order.stockit?
- %th Verfügbar
- - else
- %th Herkunft
- %th Hersteller
- %th Gebinde
- %th Preis (netto/FC)
- - for category_name, articles in @order.articles_for_ordering
- %tr{:style => "background-color:#EFEFEF"}
- %td
- %td{:colspan => "6", :style => "text-align:left"}
- %b=h category_name
- - for article in articles
- / check if the article is selected
- - included = @order.order_articles.detect { |order_article| order_article.article_id == article.id }
- - included_class = included ? ' selected' : ''
- %tr{:class => cycle('even', 'odd') + ' click-me' + included_class, :id => article.id.to_s, :onclick => "checkRow('#{article.id}')"}
- %td= check_box_tag "order[article_ids][]", article.id, included, { :id => "checkbox_#{article.id}", :onclick => "checkRow('#{article.id}')" }
- %td=h article.name
- %td=h truncate article.note, :length => 25
- - if @order.stockit?
- %td= "#{article.quantity_available} * #{article.unit}"
- - else
- %td=h truncate article.origin, :length => 15
- %td=h truncate article.manufacturer, :length => 15
- %td= "#{article.unit_quantity} x #{article.unit}"
- %td= "#{number_to_currency(article.price)} / #{number_to_currency(article.fc_price)}"
- %tr
- %td{:colspan => "6"}
- = check_box_tag 'checkall', "1", false, { :onclick => "checkUncheckAll(this)" }
- Alle auswählen
+ - if (@template_orders && !@template_orders.empty?)
+ = render :partial => 'template_orders_script'
-- if (@template_orders && !@template_orders.empty?)
- = render :partial => 'template_orders_script'
\ No newline at end of file
+ .form-actions
+ = f.submit class: 'btn'
+ = link_to t('ui.or_cancel'), orders_path
diff --git a/app/views/orders/_orders.html.haml b/app/views/orders/_orders.html.haml
index fae435e2..baa5b815 100644
--- a/app/views/orders/_orders.html.haml
+++ b/app/views/orders/_orders.html.haml
@@ -1,19 +1,17 @@
= pagination_links_remote @orders, :params => {:sort => params[:sort]}
-%table.list{:style => "width: 100%"}
+%table.table.table-striped
%thead
%tr
- %th[sort_td_class_helper "supplier"]
- = sort_link_helper "Lieferantin", "supplier"
- %th Start
- %th[sort_td_class_helper "ends"]
- = sort_link_helper "Ende", "ends"
- %th Status
+ %th= sort_link_helper t('.supplier'), "supplier"
+ %th= t '.start'
+ %th= sort_link_helper t('.ending'), "ends"
+ %th= t '.status'
%th{:colspan => "2"}
%tbody
- @orders.each do |order|
- %tr{:class => cycle('even', 'odd', :name => 'orders')}
- %td=h order.name
- %td=h format_time(order.starts)
- %td=h format_time(order.ends)
- %td= order.state
- %td= link_to "Anzeigen", order
\ No newline at end of file
+ %tr
+ %td= order.name
+ %td= format_time(order.starts)
+ %td= format_time(order.ends)
+ %td= t(order.state, scope: 'orders.state')
+ %td= link_to t('ui.show'), order, class: 'btn btn-small'
diff --git a/app/views/orders/_template_orders_script.html.erb b/app/views/orders/_template_orders_script.html.erb
deleted file mode 100644
index da9c2b33..00000000
--- a/app/views/orders/_template_orders_script.html.erb
+++ /dev/null
@@ -1,20 +0,0 @@
-
\ No newline at end of file
diff --git a/app/views/orders/articlesPdf.pdf.prawn b/app/views/orders/articlesPdf.pdf.prawn
deleted file mode 100644
index 0a4745cb..00000000
--- a/app/views/orders/articlesPdf.pdf.prawn
+++ /dev/null
@@ -1,36 +0,0 @@
-end_date = @order.ends.strftime('%d.%m.%Y')
-title = "#{@order.name} | beendet am #{end_date}"
-
-# Define header and footer
-pdf.header [pdf.margin_box.left,pdf.margin_box.top+30] do
- pdf.text title, :size => 10, :align => :center
-end
-pdf.footer [pdf.margin_box.left, pdf.margin_box.bottom-5] do
- pdf.stroke_horizontal_rule
- pdf.text "Seite #{pdf.page_count}", :size => 8
-end
-
-# Start rendering
-
-for order_article in @order.order_articles.ordered
- pdf.text "#{order_article.article.name} (#{order_article.article.unit} |\
-#{order_article.price.unit_quantity.to_s} | #{number_to_currency(order_article.price.fc_price)})",
- :style => :bold, :size => 10
- pdf.move_down 5
- data = []
- for goa in order_article.group_order_articles
- data << [goa.group_order.ordergroup.name,
- goa.result,
- number_with_precision(order_article.price.fc_price * goa.result)]
- end
-
- pdf.table data,
- :font_size => 8,
- :headers => ["Bestellgruppe", "Menge", "Preis"],
- :widths => { 0 => 200, 1 => 40, 2 => 40 },
- :border_style => :grid,
- :row_colors => ['ffffff','ececec'],
- :vertical_padding => 3,
- :align => { 2 => :right }
- pdf.move_down 10
-end
diff --git a/app/views/orders/edit.html.haml b/app/views/orders/edit.html.haml
index 7f3095bc..914993dc 100644
--- a/app/views/orders/edit.html.haml
+++ b/app/views/orders/edit.html.haml
@@ -1,7 +1,3 @@
-- title _("Edit order")
+- title t('.title')
-- form_for @order do |form|
- = render :partial => 'form', :locals => { :form => form }
- = submit_tag "Speichern"
- |
- = link_to "Abbrechen", :action => 'show', :id => @order
\ No newline at end of file
+= render :partial => 'form'
diff --git a/app/views/orders/faxPdf.pdf.prawn b/app/views/orders/faxPdf.pdf.prawn
deleted file mode 100644
index 5294b0b6..00000000
--- a/app/views/orders/faxPdf.pdf.prawn
+++ /dev/null
@@ -1,53 +0,0 @@
-# Get ActiveRecord objects
-contact = Foodsoft.config[:contact].symbolize_keys
-
-# Define header and footer
-#pdf.header [pdf.margin_box.left,pdf.margin_box.top+30] do
-# pdf.text title, :size => 10, :align => :center
-#end
-pdf.footer [pdf.margin_box.left, pdf.margin_box.bottom-5] do
- pdf.stroke_horizontal_rule
- pdf.text "Seite #{pdf.page_count}", :size => 8
-end
-
-# From paragraph
-pdf.bounding_box [pdf.margin_box.right-200,pdf.margin_box.top], :width => 200 do
- pdf.text Foodsoft.config[:name], :align => :right
- pdf.move_down 5
- pdf.text contact[:street], :align => :right
- pdf.move_down 5
- pdf.text contact[:zip_code] + " " + contact[:city], :align => :right
- pdf.move_down 10
- pdf.text contact[:phone], :size => 9, :align => :right
- pdf.move_down 5
- pdf.text contact[:email], :size => 9, :align => :right
-end
-
-# Recipient
-pdf.bounding_box [pdf.margin_box.left,pdf.margin_box.top-60], :width => 200 do
- pdf.text @order.name
- pdf.move_down 5
- pdf.text @order.supplier.address
- pdf.move_down 5
- pdf.text "Fax: " + @order.supplier.fax
-end
-
-pdf.text Date.today.strftime('%d.%m.%Y'), :align => :right
-
-pdf.move_down 10
-pdf.text "Lieferdatum:"
-pdf.move_down 10
-pdf.text "Ansprechpartner: " + @order.supplier.contact_person
-pdf.move_down 10
-
-# Articles
-data = @order.order_articles.ordered.all(:include => :article).collect do |a|
- [a.article.order_number, a.units_to_order, a.article.name,
- a.price.unit_quantity, a.article.unit, a.price.price]
-end
-pdf.table data,
- :font_size => 8,
- :vertical_padding => 3,
- :border_style => :grid,
- :headers => ["BestellNr.", "Menge","Name", "Gebinde", "Einheit","Preis/Einheit"],
- :align => {0 => :left}
\ No newline at end of file
diff --git a/app/views/orders/groupsPdf.pdf.prawn b/app/views/orders/groupsPdf.pdf.prawn
deleted file mode 100644
index a6af4d5c..00000000
--- a/app/views/orders/groupsPdf.pdf.prawn
+++ /dev/null
@@ -1,48 +0,0 @@
-end_date = @order.ends.strftime('%d.%m.%Y')
-title = "Gruppensortierung für #{@order.name}, beendet am #{end_date}"
-
-# Define header and footer
-pdf.header [pdf.margin_box.left,pdf.margin_box.top+20] do
- pdf.text title, :size => 10, :align => :center
-end
-pdf.footer [pdf.margin_box.left, pdf.margin_box.bottom-5] do
- pdf.stroke_horizontal_rule
- pdf.text "Seite #{pdf.page_count}", :size => 8
-end
-
-
-# Start rendering
-groups = @order.group_orders.size
-counter = 1
-for group_order in @order.group_orders
- pdf.text group_order.ordergroup.name, :style => :bold
- pdf.move_down 5
- pdf.text "Gruppe #{counter.to_s}/#{groups.to_s}", :size => 8
- pdf.move_down 5
-
- total = 0
- data = []
- group_order.group_order_articles.ordered.each do |goa|
- price = goa.order_article.price.fc_price
- sub_total = price * goa.result
- total += sub_total
- data << [goa.order_article.article.name,
- goa.result, number_with_precision(price),
- goa.order_article.price.unit_quantity,
- goa.order_article.article.unit,
- number_with_precision(sub_total)]
- end
- data << [ {:text => "Summe", :colspan => 5}, number_with_precision(total)]
-
- pdf.table data,
- :font_size => 8,
- :border_style => :grid,
- :vertical_padding => 3,
- :headers => ["Artikel", "Menge", "Preis", "GebGr", "Einheit", "Summe"],
- :widths => { 0 => 250 },
- :row_colors => ['ffffff','ececec'],
- :align => { 0 => :right, 5 => :right }
-
- counter += 1
- pdf.move_down 10
-end
\ No newline at end of file
diff --git a/app/views/orders/index.haml b/app/views/orders/index.haml
deleted file mode 100644
index c2ba250f..00000000
--- a/app/views/orders/index.haml
+++ /dev/null
@@ -1,43 +0,0 @@
-- title "Bestellungen verwalten"
-
-- if @current_user.role_orders?
- %p
- - form_tag do
- Neue Bestellung anlegen für
- %select{:onchange => "redirectTo(this)", :style => "font-size: 0.9em;margin-left:1em;"}
- %option{:selected => 'selected'} Lieferantin auswählen...
- = options_for_suppliers_to_select
-%br/
-.left_column{:style => "width:55em"}
- .box_title
- %h2 Laufende Bestellungen
- .column_content
- - unless @open_orders.empty?
- %table.list
- %thead
- %tr
- %th Lieferantin
- %th Ende
- %th Notiz
- %th{:colspan => "2"}
- %tbody
- - for order in @open_orders
- - tr_class = cycle('even', 'odd', :name => 'open_orders')
- - tr_class += " active" if order.expired?
- %tr{:class => tr_class}
- %td=h order.name
- %td=h format_time(order.ends) unless order.ends.nil?
- %td=h truncate(order.note)
- %td= link_to "Beenden", finish_order_path(order), :confirm => "Willst Du wirklich die Bestellung \"#{order.name}\" beenden?\nEs gibt kein zurück.", :method => :post
- %td
- = link_to "Anzeigen", order
- = link_to icon(:edit), edit_order_path(order)
- = link_to icon(:delete), order, :confirm => "Bist Du sicher die Bestellung zu beenden?", :method => :delete
- - else
- Derzeit gibt es keine laufende Bestellungen.
-
-.left_column{:style => "width:75em"}
- .box_title
- %h2 Beendete Bestellungen
- .column_content#orders_table
- = render :partial => 'orders'
\ No newline at end of file
diff --git a/app/views/orders/index.html.haml b/app/views/orders/index.html.haml
new file mode 100644
index 00000000..7960b07f
--- /dev/null
+++ b/app/views/orders/index.html.haml
@@ -0,0 +1,43 @@
+- title t('.title')
+
+- content_for :actionbar do
+ .btn-group
+ = link_to '#', data: {toggle: 'dropdown'}, class: 'btn btn-primary dropdown-toggle' do
+ = t '.new_order'
+ %span.caret
+ %ul.dropdown-menu
+ - Supplier.undeleted.order('suppliers.name ASC').each do |supplier|
+ %li= link_to supplier.name, new_order_path(supplier_id: supplier.id), tabindex: -1
+
+.well
+ %h2= t '.open_orders'
+ - unless @open_orders.empty?
+ %table.table.table-striped
+ %thead
+ %tr
+ %th= t '.supplier'
+ %th= t '.ending'
+ %th= t '.note'
+ %th{colspan: "2"}
+ %tbody
+ - for order in @open_orders
+ - tr_class = " active" if order.expired?
+ %tr{class: tr_class}
+ %td= order.name
+ %td= format_time(order.ends) unless order.ends.nil?
+ %td= truncate(order.note)
+ %td= link_to t('.action_end'), finish_order_path(order),
+ confirm: t('.confirm_end', order: order.name), method: :post,
+ class: 'btn btn-small btn-success'
+
+ %td
+ = link_to t('ui.show'), order, class: 'btn btn-small'
+ = link_to t('ui.edit'), edit_order_path(order), class: 'btn btn-small'
+ = link_to t('ui.delete'), order, confirm: t('.confirm_delete'), method: :delete,
+ class: 'btn btn-small btn-danger'
+ - else
+ = t '.no_open_orders'
+
+%h2= t '.ended_orders'
+#orders_table
+ = render partial: 'orders'
diff --git a/app/views/orders/index.js.haml b/app/views/orders/index.js.haml
new file mode 100644
index 00000000..3fd3db1c
--- /dev/null
+++ b/app/views/orders/index.js.haml
@@ -0,0 +1 @@
+$('#orders_table').html('#{escape_javascript(render('orders'))}');
\ No newline at end of file
diff --git a/app/views/orders/matrixPdf.pdf.prawn b/app/views/orders/matrixPdf.pdf.prawn
deleted file mode 100644
index 0a0a456b..00000000
--- a/app/views/orders/matrixPdf.pdf.prawn
+++ /dev/null
@@ -1,83 +0,0 @@
-title = "#{@order.name}, beendet am #{@order.ends.strftime('%d.%m.%Y')}"
-
-# Define header and footer
-pdf.header [pdf.margin_box.left,pdf.margin_box.top+20] do
- pdf.text title, :size => 10, :align => :center
-end
-pdf.footer [pdf.margin_box.left, pdf.margin_box.bottom-5] do
- pdf.stroke_horizontal_rule
- pdf.move_down 2
- pdf.text "Seite #{pdf.page_count}", :size => 8
-end
-
-max_order_articles_per_page = 16 # How many order_articles shoud written on a page
-order_articles = @order.order_articles.ordered
-
-pdf.text "Artikelübersicht", :style => :bold
-pdf.move_down 5
-pdf.text "Insgesamt #{order_articles.size} Artikel", :size => 8
-pdf.move_down 10
-
-order_articles_data = order_articles.collect do |a|
- [a.article.name, a.article.unit, a.price.unit_quantity, number_with_precision(a.price.fc_price), a.units_to_order]
-end
-pdf.table order_articles_data,
- :font_size => 8,
- :border_style => :grid,
- :vertical_padding => 3,
- :headers => ["Artikel", "Einheit", "Gebinde", "FC-Preis", "Menge"],
- :align => { 3 => :right }
-
-
-page_number = 0
-total_num_order_articles = order_articles.size
-
-while (page_number * max_order_articles_per_page < total_num_order_articles) do # Start page generating
-
- page_number += 1
- pdf.start_new_page(:layout => :landscape)
- pdf.header [pdf.margin_box.left,pdf.margin_box.top+20] do
- pdf.text title, :size => 10, :align => :center
- end
-
- # Collect order_articles for this page
- current_order_articles = order_articles.select do |a|
- order_articles.index(a) >= (page_number-1) * max_order_articles_per_page and
- order_articles.index(a) < page_number * max_order_articles_per_page
- end
-
- # Make order_articles header
- header = [""]
- for header_article in current_order_articles
- name = header_article.article.name.gsub(/[-\/]/, " ").gsub(".", ". ")
- name = name.split.collect { |w| truncate(w, :length => 8, :omission => "..") }.join(" ")
- header << truncate(name, :length => 30, :omission => " ..")
- end
-
- # Collect group results
- groups_data = []
- for group_order in @order.group_orders.all(:include => :ordergroup)
-
- group_result = [truncate(group_order.ordergroup.name, :length => 20)]
-
- for order_article in current_order_articles
- # get the Ordergroup result for this order_article
- goa = order_article.group_order_articles.first :conditions => { :group_order_id => group_order.id }
- group_result << ((goa.nil? || goa.result == 0) ? "" : goa.result.to_i)
- end
- groups_data << group_result
- end
-
- # Make table
- widths = {0 => 85} # Generate widths-hash for table layout
- (max_order_articles_per_page + 1).times { |i| widths.merge!({ i => 41 }) unless i == 0 }
- logger.debug "Spaltenbreiten: #{widths.inspect}"
- pdf.table groups_data,
- :font_size => 8,
- :border_style => :grid,
- :vertical_padding => 3,
- :headers => header,
- :column_widths => widths,
- :row_colors => ['ffffff','ececec']
-
-end
\ No newline at end of file
diff --git a/app/views/orders/new.html.haml b/app/views/orders/new.html.haml
index ee3cb48a..624324db 100644
--- a/app/views/orders/new.html.haml
+++ b/app/views/orders/new.html.haml
@@ -1,7 +1,3 @@
-- title "Neue Bestellung anlegen"
+- title t('.title')
-- form_for @order do |form|
- = render :partial => 'form', :locals => { :form => form }
- = submit_tag "Bestellung online stellen"
- |
- = link_to "Abbrechen", orders_path
\ No newline at end of file
+= render 'form'
diff --git a/app/views/orders/show.haml b/app/views/orders/show.haml
deleted file mode 100644
index 77b3629e..00000000
--- a/app/views/orders/show.haml
+++ /dev/null
@@ -1,96 +0,0 @@
-- title "Bestellung: #{@order.name}"
-#element_navigation
- = link_to_unless @order.previous == @order, "<< #{@order.previous.name}", @order.previous
- |
- = link_to "Übersicht", orders_path
- |
- = link_to_unless @order.next == @order, "#{@order.next.name} >>", @order.next
-
-// Order summary
-.left_column{:style => "width:65em"}
- .box_title
- %h2 Zusammenfassung
- .column_content
- - if @order.finished? and !@order.closed?
- %p
- %b{:style => "color:red"} Bestellung wurde noch nicht abgerechnet.
- %p
- Lieferantin:
- %b=h @order.name
- - unless @order.note.empty?
- %p
- Notiz:
- =h @order.note
- %p
- Erstellt von:
- =h link_to_user_message_if_valid(@order.created_by)
- %p
- Beginn:
- %b=h format_time(@order.starts)
- |
- Ende:
- %b=h format_time(@order.ends)
- %p
- Gruppenbestellungen:
- %b= @order.group_orders.count
- = "[#{@order.group_orders.find(:all, :include => :ordergroup).collect{|g| g.ordergroup.name}.join(', ')}]"
-
- %p
- Netto/Bruttosumme aller Artikel:
- %b= "#{number_to_currency(@order.sum(:net))} / #{number_to_currency(@order.sum(:gross))}"
- %p
- Bestellte Artikel:
- %b= @order.order_articles.ordered.count
-
-
- %p
- Aktionen:
- - if @order.open?
- = link_to "Bearbeiten", edit_order_path(@order)
- |
- = link_to 'Beenden!', finish_order_path(@order), :method => :post, :confirm => "Willst Du wirklich die Bestellung beenden?\nEs gibt kein zurück.."
- |
- - unless @order.closed?
- = link_to "Löschen", @order, :confirm => "Willst du wirklich die Bestellung löschen?", :method => :delete
-
-
- - unless @order.open?
- %p
- = update_articles_link(@order, "Artikelübersicht", :normal)
- |
- = update_articles_link(@order, "Sortiert nach Gruppen", :groups)
- = link_to_pdf(@order, 'groupsPdf')
- |
- = update_articles_link(@order, "Sortiert nach Artikeln", :articles)
- = link_to_pdf(@order, 'articlesPdf')
- |
- Matrix:
- = link_to_pdf(@order, 'matrixPdf')
- |
- Faxvorlage:
- = link_to_pdf(@order, 'faxPdf')
- = link_to image_tag("text_file.png", :size => "16x16", :border => "0", :alt => "Textdatei erstellen"), { :action => 'text_fax_template', :id => @order }, { :title => _("Download file") }
- |
- = link_to 'Kommentare', '#comments'
-
-.single_column{:style => "clear:both; width:70em;"}
- .box_title
- %h2 Artikel
- .column_content#articles
- = render :partial => 'articles', :locals => { :order => @order }
-
-.single_column{:style => "width:70em;"}
- .box_title
- %h2 Kommentare
- .column_content#comments
- = render :partial => "/shared/comments", :locals => { :comments => @order.comments }
- %p
- - form_for :comment, :url => add_comment_order_path(@order) do |form|
- %p
- %b Neuen Kommentar hinzufügen:
- %br/
- = form.text_area :text, :cols => 50, :rows => 6
- %br/
- = submit_tag "Kommentar hinzufügen"
-
- = link_to_top
diff --git a/app/views/orders/show.html.haml b/app/views/orders/show.html.haml
new file mode 100644
index 00000000..0e9a3926
--- /dev/null
+++ b/app/views/orders/show.html.haml
@@ -0,0 +1,62 @@
+- title t('.title', name: @order.name)
+
+- if @order.finished? and !@order.closed?
+ .alert.alert-warning
+ = t '.warn_not_closed'
+
+// Order summary
+.well
+ %dl.dl-horizontal
+ %dt= t '.supplier'
+ %dd= @order.name
+ - if @note.present?
+ %dt= t '.note'
+ %dd= @order.note
+ %dt= t '.created_by'
+ %dd= link_to_user_message_if_valid(@order.created_by)
+ %dt= t '.begin'
+ %dd= format_time(@order.starts)
+ %dt= t '.ending'
+ %dd= format_time(@order.ends)
+ %dt= t '.group_orders'
+ %dd #{@order.group_orders.count} (#{@order.group_orders.includes(:ordergroup).all.map {|g| g.ordergroup.name}.join(', ')})
+ %dt= t '.amounts'
+ %dd= "#{number_to_currency(@order.sum(:net))} / #{number_to_currency(@order.sum(:gross))}"
+ %dt= t '.articles_ordered'
+ %dd= @order.order_articles.ordered.count
+
+
+ .form-actions
+ - if @order.open?
+ = link_to t('ui.edit'), edit_order_path(@order), class: 'btn'
+ = link_to t('.action_end'), finish_order_path(@order), method: :post, class: 'btn btn-success',
+ confirm: t('.confirm_end', order: @order.name)
+ - unless @order.closed?
+ = link_to t('ui.delete'), @order, confirm: t('.confirm_delete'), method: :delete,
+ class: 'btn btn-danger'
+
+- unless @order.open?
+ %ul.nav.nav-pills
+ %li= update_articles_link(@order, t('.articles'), :default)
+ %li= update_articles_link(@order, t('.sort_group'), :groups)
+ %li= update_articles_link(@order, t('.sort_article'), :articles)
+ %li= link_to t('.comments_link'), '#comments'
+ %li.dropdown
+ = link_to '#', class: 'dropdown-toggle', data: {toggle: 'dropdown'} do
+ = t '.download.title'
+ %b.caret
+ %ul.dropdown-menu
+ %li= order_pdf(@order, :groups, t('.download.group_pdf'))
+ %li= order_pdf(@order, :articles, t('.download.article_pdf'))
+ %li= order_pdf(@order, :matrix, t('.download.matrix_pdf'))
+ %li= order_pdf(@order, :fax, t('.download.fax_pdf'))
+ %li= link_to t('.download.fax_txt'), {action: 'text_fax_template', id: @order }, {title: t('.download.download_file')}
+
+%section#articles_table
+ = render 'articles', order: @order
+
+%h2= t '.comments.title'
+#comments
+ = render partial: 'shared/comments', locals: { comments: @order.comments }
+#new_comment= render partial: 'order_comments/form', locals: { order_comment: @order.comments.build(user: current_user)}
+= link_to_top
diff --git a/app/views/orders/show.js.haml b/app/views/orders/show.js.haml
new file mode 100644
index 00000000..da1e0a4a
--- /dev/null
+++ b/app/views/orders/show.js.haml
@@ -0,0 +1,2 @@
+$('#articles_table').html('#{escape_javascript(render(@partial, order: @order))}');
+
diff --git a/app/views/pages/_body.html.haml b/app/views/pages/_body.html.haml
index 49fb353a..cc06bc6b 100644
--- a/app/views/pages/_body.html.haml
+++ b/app/views/pages/_body.html.haml
@@ -1,9 +1,9 @@
- content = wikified_body @page.body, @page.title
- toc = generate_toc @page.body
-- unless toc.blank?
- #wikitoc
- %h2
- Inhaltsverzeichnis
- %span= link_to_function "[verstecken]", "Element.toggle('wikitoc-content')"
- #wikitoc-content= toc
-#wiki_content= content
\ No newline at end of file
+
+- unless toc.blank? or params[:preview]
+ - content_for :sidebar do
+ #wikitoc.well.well-small
+ %h3= t '.title_toc'
+ = toc
+= content
diff --git a/app/views/pages/_form.html.haml b/app/views/pages/_form.html.haml
index 40e3a466..a3de5652 100644
--- a/app/views/pages/_form.html.haml
+++ b/app/views/pages/_form.html.haml
@@ -1,102 +1,85 @@
- if params[:preview]
- %h2 Vorschau
- #preview= render :partial => 'body'
+ %section#wikiContent
+ = render 'body'
-#wiki-syntax-help
- .box_title
- %h2 Schnelle Formatierungshilfe
- .column_content
- %table(frame="void")
+.row-fluid
+ .span8
+ = simple_form_for @page do |f|
+ = f.hidden_field :lock_version
+ = f.input :title, input_html: {class: 'input-xxlarge'}
+ = f.input :body, input_html: {class: 'input-xxlarge'}
+ = f.input :parent_id, as: :select, collection: parent_pages_to_select(@page)
+ .form-actions
+ = button_tag :name => 'preview', class: 'btn' do
+ %i.icon-search= t '.preview'
+ = button_tag class: 'btn' do
+ %i.icon-save= t 'ui.save'
+ = link_to t('ui.or_cancel'), @page
+
+ .span4
+ %h3= t '.help.title'
+ %table.table
%tbody
%tr
%td(colspan=2)
- %b Zeichenformatierung
+ %b= t '.help.section_character'
%tr
%td
- %i kursiv
+ %i= t '.help.italic'
%td
%pre
- ''kursiv''
+ ''#{t '.help.italic'}''
%tr
%td
- %b fett
+ %b= t '.help.bold'
%td
- %pre '''Fett'''
+ %pre '''#{t '.help.bold'}'''
%tr
+ %td= t '.help.noformat'
%td
- Keine Wiki- Formatierung
- %td
- %pre <nowiki>text</nowiki>
+ %pre <nowiki>#{t '.help.text'}</nowiki>
%tr
%td(colspan=2)
- %b Block-Formatierung
+ %b= t '.help.section_block'
%tr
- %td
- Überschriften
+ %td= t '.help.headings'
%td
%pre
- \== Ebene 1 ==
+ \== #{t '.help.heading', level: 1} ==
%pre
- \=== Ebene 2 ===
+ \=== #{t '.help.heading', level: 2} ===
%pre
- \==== Ebene 3 ====
+ \==== #{t '.help.heading', level: 3} ====
%tr
- %td
- Listen mit Punkten
+ %td= t '.help.unordered_list'
%td
%pre
- * Erster Punkt
+ * #{t '.help.list_item_1'}
%pre
- ** Zweiter Punkt
+ ** #{t '.help_list_item_2'}
%tr
- %td
- Listen mit Zahlen
+ %td= t '.help.ordered_list'
%td
%pre
- \# Ersten Punkt
+ \# #{t '.help.list_item_1'}
%pre
- \# Zweiter Punkt
+ \# #{t '.help.list_item_2'}
%tr
%td(colspan=2)
- %b Link-Formatierung
+ %b= t '.help.section_link'
%tr
- %td
- Wiki-Links
+ %td= t '.help.wiki_links'
%td
%pre
- [[Foodsoft Wiki Seite]]
+ [[#{t '.help.wiki_link_ex'}]]
%tr
- %td
- Externe Links
+ %td= t '.help.external_links'
%td
%pre
- [http://addresse.net Externe Seite]
+ [http://example.net #{t '.help.external_link_ex'}]
%tr
%td(colspan=2)
- %b Tabellenformatierung
+ %b= t '.help.section_table'
%tr
- %td
- Siehe
- = link_to "Tabellen", "http://www.mediawiki.org/wiki/Help:Tables", :target => '_blank'
+ %td!= t '.help.see_tables', tables_link: link_to(t('.help.tables_link'), "http://www.mediawiki.org/wiki/Help:Tables", :target => '_blank')
-- form_for @page do |f|
- = f.error_messages
- = f.hidden_field :lock_version
- %p
- %b Titel
- %br/
- = f.text_field :title
- %p
- %b Inhalt
- %br/
- = f.text_area :body, :size => "65x30"
- %p
- = f.submit "Vorschau", :name => 'preview'
- |
- = f.submit "Speichern"
- |
- = link_to "Abbrechen", @page
- | Oberseite ändern:
- = collection_select(:page, :parent_id, parent_pages_to_select(@page), :id, :permalink, {:prompt => "Neue Oberseite?", :include_blank => true})
-
-%div(style="clear:right; height:1px")
diff --git a/app/views/pages/_page_list_item.html.haml b/app/views/pages/_page_list_item.html.haml
index 1e7f3c89..496e0720 100644
--- a/app/views/pages/_page_list_item.html.haml
+++ b/app/views/pages/_page_list_item.html.haml
@@ -2,7 +2,7 @@
%tr
%td{:style => "padding-left: #{ident}px"}
= link_to page.title, wiki_page_path(page.permalink)
- %td= "#{User.find(page.updated_by).nick} (#{format_datetime_timespec(page.updated_at, '%a, %d. %B %Y %H:%M:%S')})"
+ %td #{page.user.try(:nick)} (#{format_datetime_timespec(page.updated_at, t('.date_format'))})
-if siteMap == 1
-for child in page.children.all
- = render :partial => 'page_list_item', :locals => {:page => child, :level => level+1, :siteMap => 1}
\ No newline at end of file
+ = render :partial => 'page_list_item', :locals => {:page => child, :level => level+1, :siteMap => 1}
diff --git a/app/views/pages/_recent_changes.html.haml b/app/views/pages/_recent_changes.html.haml
index 213ca5f8..50d301dc 100644
--- a/app/views/pages/_recent_changes.html.haml
+++ b/app/views/pages/_recent_changes.html.haml
@@ -1,7 +1,8 @@
-.column_content
- %table
+%table.table.table-striped
+ %thead
%tr
- %th Titel
- %th Zuletzt aktualisiert
- - for page in @recent_pages
+ %th= t 'pages.title'
+ %th= t 'pages.last_updated'
+ %tbody
+ - for page in @pages
= render :partial => "page_list_item", :locals => {:page => page, :level => 0, :siteMap => 0}
diff --git a/app/views/pages/_site_map.html.haml b/app/views/pages/_site_map.html.haml
index dc31505a..d3e9681f 100644
--- a/app/views/pages/_site_map.html.haml
+++ b/app/views/pages/_site_map.html.haml
@@ -1,11 +1,12 @@
-.column_content
- %table
+%table.table.table-striped
+ %thead
%tr
- %th Titel
- %th Zuletzt aktualisiert
+ %th= t 'pages.title'
+ %th= t 'pages.last_updated'
- homepage = Page.find_by_permalink('Home')
- unless homepage.nil?
= render :partial => 'page_list_item', :locals => {:page => homepage, :level => 0, :siteMap => 1}
- - for page in @top_pages
- - if page.id != homepage.id
+ %tbody
+ - for page in @pages
+ - if page.id != homepage.try(:id)
= render :partial => 'page_list_item', :locals => {:page => page, :level => 0, :siteMap => 1}
diff --git a/app/views/pages/_title_list.html.haml b/app/views/pages/_title_list.html.haml
index 855a37bf..50d301dc 100644
--- a/app/views/pages/_title_list.html.haml
+++ b/app/views/pages/_title_list.html.haml
@@ -1,7 +1,8 @@
-.column_content
- %table
+%table.table.table-striped
+ %thead
%tr
- %th Titel
- %th Zuletzt aktualisiert
+ %th= t 'pages.title'
+ %th= t 'pages.last_updated'
+ %tbody
- for page in @pages
- = render :partial => "page_list_item", :locals => {:page => page, :level => 0, :siteMap => 0}
\ No newline at end of file
+ = render :partial => "page_list_item", :locals => {:page => page, :level => 0, :siteMap => 0}
diff --git a/app/views/pages/all.html.haml b/app/views/pages/all.html.haml
index 49f3fd74..bb57e33c 100644
--- a/app/views/pages/all.html.haml
+++ b/app/views/pages/all.html.haml
@@ -1,21 +1,17 @@
-- title "Alle Wikiseiten", false
+- title t('.title'), false
-.wiki_all
- #breadcrump
- = link_to_wikipage_by_permalink("Home", "Foodcoop-Wiki")
+- content_for :sidebar do
+ = link_to t('.new_page'), new_page_path, class: 'btn btn-primary'
- %h1 Alle Wikiseiten
+.navbar
+ .navbar-inner
+ %ul.nav
+ %li= link_to t('.recent_changes'), all_pages_path(:view => 'recent_changes')
+ %li= link_to t('.title_list'), all_pages_path(:view => 'title_list')
+ %li= link_to t('.site_map'), all_pages_path(:view => 'site_map')
+ = form_tag all_pages_path, method: :get, class: 'form-search pull-right' do
+ = text_field_tag :name, params[:name], class: 'input-medium search-query',
+ placeholder: t('.search.placeholder')
+ = submit_tag t('.search.action'), class: 'btn'
-
- #sidebar
- #sidebar-links
- = link_to "Neue Seite anlegen", new_page_path
-
- .left_column{:style => "width:100%"}
- .box_title
- #editOrderNav
- = remote_link_to 'Letzte Änderungen', :update => 'left_column', :url => {:action => 'all', :view => 'recentChanges'}
- = remote_link_to 'Seiten-Liste', :update => 'left_column', :url => {:action => 'all', :view => 'titleList'}
- = remote_link_to 'Site Map', :update => 'left_column', :url => {:action => 'all', :view => 'siteMap'}
- #left_column
- = render :partial => 'recent_changes'
\ No newline at end of file
+= render @partial
diff --git a/app/views/pages/edit.html.haml b/app/views/pages/edit.html.haml
index 2d065b1a..624324db 100644
--- a/app/views/pages/edit.html.haml
+++ b/app/views/pages/edit.html.haml
@@ -1,14 +1,3 @@
-- title "#{@page.title} bearbeiten", false
+- title t('.title')
-.wiki_edit
- #breadcrump
- = link_to_wikipage_by_permalink("Home", "Foodcoop-Wiki")
- - for page in @page.ancestors.reverse
- %span.wikiSeparator >
- = link_to_wikipage(page)
- %span.wikiSeparator >
- = link_to_wikipage(@page)
-
- %h1 #{@page.title} bearbeiten
-
- = render :partial => 'form'
+= render 'form'
diff --git a/app/views/pages/new.html.haml b/app/views/pages/new.html.haml
index 8bb44198..624324db 100644
--- a/app/views/pages/new.html.haml
+++ b/app/views/pages/new.html.haml
@@ -1,16 +1,3 @@
-- title "Neue Wikiseite anlegen", false
+- title t('.title')
-.wiki_new
- #breadcrump
- = link_to_wikipage_by_permalink("Home", "Foodcoop-Wiki")
- - parent_page = Page.find_by_permalink(params[:parent])
- - if parent_page != nil
- - for page in parent_page.ancestors.reverse
- %span.wikiSeparator >
- = link_to_wikipage(page)
- %span.wikiSeparator >
- = @page.title
-
- %h1 Neue Wikiseite anlegen
-
- = render :partial => 'form'
+= render 'form'
diff --git a/app/views/pages/show.html.haml b/app/views/pages/show.html.haml
index de3f79cd..2c1d0bb1 100644
--- a/app/views/pages/show.html.haml
+++ b/app/views/pages/show.html.haml
@@ -1,51 +1,51 @@
- title @page.title, false
-.wiki_show
-
- #breadcrump
- = link_to_wikipage_by_permalink("Home", "Foodcoop-Wiki")
- - for page in @page.ancestors.reverse
- %span.wikiSeparator >
- = link_to_wikipage(page)
- %span.wikiSeparator >
- = @page.title
-
- %h1
- = @page.title
-
- #sidebar
- #sidebar-links
- = link_to "Bearbeiten", edit_page_path(@page)
- = link_to_function "Versionen (#{@page.versions.count})", "Element.toggle('versions')"
+- content_for :sidebar do
+ %p
+ = link_to edit_page_path(@page), class: 'btn btn-primary' do
+ %i.icon-edit= t '.edit'
+ .well.well-small
+ %ul.nav.nav-list
+ %li
+ %li= link_to t('.versions', count: @page.versions.count), "#versions", 'data-toggle-this' => '#versions'
- unless @page.children.empty?
- = link_to_function "Unterseiten", "Element.toggle('subpages')"
- #versions{:style => "display:none"}
- .box_title
- %h2 Versionen
- .column_content
- %ul
- - for version in @page.versions.reverse
- %li
- = link_to I18n.l(version.updated_at, :format => "%d.%m.%y %H:%M"), version_page_path(@page, :version => version.lock_version)
- = "(#{User.find_by_id(version.updated_by).try(:nick)})"
+ %li= link_to t('.subpages'), "#subpages", 'data-toggle-this' => '#subpages'
- - unless @page.children.empty?
- #subpages{:style => "display:none"}
- .box_title
- %h2 Unterseiten
- .column_content
- %ul
- - for page in @page.children
- %li= link_to_wikipage(page)
+ #versions.well.well-small{:style => "display:none"}
+ %h3= t '.title_versions'
+ %ul.unstyled
+ - @page.versions.reverse.each do |version|
+ %li
+ = link_to I18n.l(version.updated_at, :format => t('.date_format')), version_page_path(@page, :version => version.lock_version)
+ = "(#{User.find_by_id(version.updated_by).try(:nick)})"
+ - unless @page.children.empty?
+ #subpages.well.well-small{:style => "display:none"}
+ %h3= t '.subpages'
+ %ul.unstyled
+ - @page.children.each do |page|
+ %li= link_to_wikipage(page)
+
+%ul.breadcrumb
+ %li
+ = link_to_wikipage_by_permalink("Home", "Foodcoop-Wiki")
+ %span.divider /
+ - for page in @page.ancestors.reverse
+ %li
+ = link_to_wikipage(page)
+ %span.divider /
+ %li.active= @page.title
+
+
+#wikiContent
+ .page-header
+ %h1= @page.title
= render :partial => 'body'
- %hr.clear/
- %p
- = link_to "Seite bearbeiten", edit_page_path(@page)
- |
- = link_to "Seite löschen", @page, :method => :delete, :confirm => "Achtung, auch alle Unterseiten werden gelöscht. Bist Du sicher?"
- | Zuletzt bearbeitet von
- %b
- = "#{@page.user.try(:nick)}"
- = "am #{format_datetime @page.updated_at}"
+%hr.clear/
+%p
+ = link_to edit_page_path(@page), class: 'btn btn-primary' do
+ %i.icon-edit= t '.edit'
+ = link_to t('.delete'), @page, class: 'btn btn-danger', :method => :delete,
+ :confirm => t('.delete_confirm')
+ != '| ' + t('.last_updated', user: h(@page.user.try(:nick)), when: format_datetime(@page.updated_at))
diff --git a/app/views/pages/version.html.haml b/app/views/pages/version.html.haml
index 369fa375..222b465d 100644
--- a/app/views/pages/version.html.haml
+++ b/app/views/pages/version.html.haml
@@ -1,27 +1,11 @@
-- title @page.title, false
+- title t('.title', title: @page.title, version: @version.lock_version)
-.wiki_version
- #breadcrump
- = link_to_wikipage_by_permalink("Home", "Foodcoop-Wiki")
- - for page in @page.ancestors.reverse
- %span.wikiSeparator >
- = link_to_wikipage(page)
- %span.wikiSeparator >
- = link_to_wikipage(@page)
-
- %h1
- = @page.title
-
- #sidebar
- .box_title
- %h2 Version
- .column_content
- %b= "#{format_datetime_timespec(@version.updated_at, "%a, %d.%m.%Y, %H:%M Uhr") }"
- %ul
- %li= "Autor: #{User.find(@version.updated_by).nick}"
- %li= link_to "Aktuelle Version sehen", wiki_page_path(:permalink => @page.permalink)
- %li= link_to "Auf diese Version zurücksetzen", revert_page_path(@page, :version => @version.lock_version)
-
- = wikified_body @version.body
- %div(style="clear:right")
+- content_for :sidebar do
+ %h3= t '.title_version'
+ %b= "#{format_datetime_timespec(@version.updated_at, t('.date_format'))}"
+ %ul
+ %li= t '.author', user: User.find(@version.updated_by).nick
+ %li= link_to t('.view_current'), wiki_page_path(:permalink => @page.permalink)
+ %li= link_to t('.revert'), revert_page_path(@page, :version => @version.lock_version)
+= wikified_body @version.body
diff --git a/app/views/sessions/new.html.haml b/app/views/sessions/new.html.haml
new file mode 100644
index 00000000..c0026150
--- /dev/null
+++ b/app/views/sessions/new.html.haml
@@ -0,0 +1,27 @@
+- content_for :javascript do
+ :javascript
+ $(function() {
+ $('#nick').focus();
+ });
+
+- title t('.title')
+
+%noscript
+ .alert.alert-error
+ != t '.nojs', link: link_to(t('.noscript'), "http://noscript.net/")
+
+= form_tag sessions_path, class: 'form-horizontal' do
+ .control-group
+ %label(for='nick' class='control-label')= t '.user'
+ .controls
+ = text_field_tag 'nick'
+
+ .control-group
+ %label(for='password' class='control-label')= t '.password'
+ .controls
+ = password_field_tag 'password'
+
+ .control-group
+ .controls
+ = submit_tag t('.login'), class: 'btn'
+ = link_to t('.forgot_password'), forgot_password_path
diff --git a/app/views/shared/_articles_by_articles.html.haml b/app/views/shared/_articles_by_articles.html.haml
index 340a1d2b..df4528a3 100644
--- a/app/views/shared/_articles_by_articles.html.haml
+++ b/app/views/shared/_articles_by_articles.html.haml
@@ -1,15 +1,12 @@
-.legend
- %table.legend{:style => "margin-bottom:1em"}
+%table.table.table-hover
+ %thead
%tr
- %th{:colspan => '3'} Legende
- %tr
- %th{:style => 'width:70%'} Bestellgruppe
- %th Bestellt (Menge + Toleranz)
- %th Bekommen
- %th Gesamtpreis
+ %th{:style => 'width:70%'}= t '.ordergroup'
+ %th= t '.ordered'
+ %th= t '.received'
+ %th= t '.price'
-- for order_article in order.order_articles.ordered.all(:include => [:article, :article_price])
- %table{:style => "margin-bottom:1em"}
+ - for order_article in order.order_articles.ordered.all(:include => [:article, :article_price])
%thead
%tr
%th{:colspan => "4"}
@@ -23,4 +20,6 @@
%td
%b= goa.result
%td= number_to_currency(order_article.price.fc_price * goa.result)
- - reset_cycle('groups')
\ No newline at end of file
+ %tr
+ %td(colspan="4" )
+ - reset_cycle('groups')
diff --git a/app/views/shared/_articles_by_groups.html.haml b/app/views/shared/_articles_by_groups.html.haml
index 486973e6..c78f5a70 100644
--- a/app/views/shared/_articles_by_groups.html.haml
+++ b/app/views/shared/_articles_by_groups.html.haml
@@ -1,21 +1,21 @@
-.legend
- %table.legend{:style => "margin-bottom:1em"}
+%table.table.table-hover
+ %thead
%tr
- %th{:style => "width:40%"} Name
+ %th{:style => "width:40%"}= t '.name'
%th
- %acronym{:title => "zugeteilte Einheiten"} Menge
+ %acronym{:title => t('.units_desc')}= t '.units'
%th
- %acronym{:title => "Preis incl. MwSt, Pfand und Foodcoop-Aufschlag"} FC-Preis
+ %acronym{:title => t('.fc_price_desc')}= t '.fc_price'
%th
- %acronym{:title => "Gebindegröße"} GebGr
- %th Einheit
- %th Gesamtpreis
+ %acronym{:title => t('.unit_quantity_desc')}= t '.unit_quantity'
+ %th= t '.unit'
+ %th= t '.price'
-- for group_order in order.group_orders.all
- %table{:style => "margin-bottom:1em"}
+ - for group_order in order.group_orders.all
%thead
%tr
- %th{:colspan => "6"}=h group_order.ordergroup.name
+ %th{:colspan => "6"}
+ %h4= group_order.ordergroup.name
%tbody
- total = 0
- for goa in group_order.group_order_articles.ordered.all(:include => :order_article)
@@ -33,4 +33,6 @@
%tr{:class => cycle('even', 'odd', :name => 'articles')}
%th{:colspan => "5"} Summe
%th= number_to_currency(total)
- - reset_cycle("articles")
\ No newline at end of file
+ %tr
+ %th(colspan="6")
+ - reset_cycle("articles")
diff --git a/app/views/shared/_comments.haml b/app/views/shared/_comments.haml
index 7fdea92d..27da9138 100644
--- a/app/views/shared/_comments.haml
+++ b/app/views/shared/_comments.haml
@@ -1,9 +1,5 @@
-- unless comments.empty?
- - comments.each do |comment|
- .comment[comment]
- .timestamp
- %b=h "#{comment.user.try(:ordergroup_name)}"
- = "(#{comment.user.try(:nick)} am #{format_time(comment.created_at)}):"
- = simple_format(comment.text)
-- else
- es gibt derzeit keine Kommentare.
\ No newline at end of file
+- comments.each do |comment|
+ .comment[comment]
+ %strong= comment.user.try(:ordergroup_name)
+ %small (#{comment.user.try(:nick)} am #{format_time(comment.created_at)}):
+ = simple_format(comment.text)
diff --git a/app/views/shared/_group.html.haml b/app/views/shared/_group.html.haml
index 18dcb60b..eebe4cac 100644
--- a/app/views/shared/_group.html.haml
+++ b/app/views/shared/_group.html.haml
@@ -1,28 +1,25 @@
-%table
- %tr
- %td Beschreibung:
- %td=h group.description
+%dl
+ %dt= t('.description') + ':'
+ %dd=h group.description
- if group.is_a?(Ordergroup) and (@current_user.role_admin? or @current_user.role_finance?)
- %tr
- %td Kontakt:
- %td=h group.contact
- %tr
- %td Adresse:
- %td= link_to_gmaps group.contact_address
- %tr
- %td Gruppe hat Zugriff auf:
- %td= format_roles(group)
- %tr
- %td Mitglieder:
- %td
- - members = group.users
- = "(#{members.size})"
- = members.collect(&:nick).join(", ")
+ %dt= t('.contact') + ':'
+ %dd=h group.contact
+ %dt= t('.address') + ':'
+ %dd= link_to_gmaps group.contact_address
+ %dt= t('.access') + ':'
+ %dd= format_roles(group)
+ %dt= t('.members') + ':'
+ %dd
+ - members = group.users
+ = "(#{members.size})"
+ = members.collect(&:nick).join(", ")
- if group.is_a?(Workgroup)
- %tr
- %td wöchentlicher Job:
- %td
- - if group.weekly_task
- =h "#{group.task_name} am #{weekday(group.weekday)}"
- - else
- kein wöchentlicher Job definiert
\ No newline at end of file
+ %dt= t('.weekly_job') + ':'
+ %dd
+ - if group.weekly_task
+ =h "#{group.task_name} am #{weekday(group.weekday)}"
+ - else
+ = t '.no_weekly_job'
+ - else
+ %dt= t '.apple_limit'
+ %dd= group.ignore_apple_restriction ? t('.deactivated') : t('.activated')
diff --git a/app/views/shared/_group_form.html.haml b/app/views/shared/_group_form.html.haml
deleted file mode 100644
index aca0d04f..00000000
--- a/app/views/shared/_group_form.html.haml
+++ /dev/null
@@ -1,67 +0,0 @@
-= @form.error_messages
-
-%div{:style => "float:left;width:55%;"}
- %p
- = @form.label :name
- %br/
- = @form.text_field :name, :size => 20
- %p
- = @form.label :description
- %br/
- = @form.text_field :description, :size => 40
-
-= yield
-
-- if @group.is_a?(Workgroup)
- %div{:style => "clear:both"}
- %h3
- Wöchentliche Jobs definieren?
- = @form.check_box :weekly_task, {:onclick => "toggleWeeklyTask();"}
- %table
- %tr
- %td
- = @form.label :weekday, "Wochentag:"
- %td
- = @form.select :weekday, Workgroup.weekdays
- %tr
- %td
- = @form.label :task_name, "Dienstname:"
- %td= @form.text_field :task_name, :size => 20
- %tr
- %td
- = @form.label :task_required_users, "Benötigte Verantwortliche:"
- %td= @form.text_field :task_required_users, :size => 3
- %tr
- %td
- = @form.label :task_duration, "Vor. Dauer in Stunden"
- %td= @form.select :task_duration, options_for_select(1..3, @group.task_duration)
- %tr
- %td
- = @form.label :task_description, "Beschreibung:"
- %td= @form.text_area :task_description, :size => "30x10"
- %tr
- %td
- = @form.label :next_weekly_tasks_number, "Für wieviel Wochen im Voraus sollen Aufgaben erstellt werden?"
- %td= @form.text_field :next_weekly_tasks_number, :size => 3
-
- %script{ 'type' => "text/javascript"}
- :plain
- //
diff --git a/app/views/shared/_group_form_fields.html.haml b/app/views/shared/_group_form_fields.html.haml
new file mode 100644
index 00000000..f13b0054
--- /dev/null
+++ b/app/views/shared/_group_form_fields.html.haml
@@ -0,0 +1,47 @@
+= f.input :name
+= f.input :description, as: :text, input_html: {rows: 4}
+
+= yield
+
+- if f.object.is_a?(Workgroup)
+ %h3= t '.title'
+ = f.input :weekly_task
+ #weekly_task_fields
+ = f.input :weekday, as: :select, collection: Workgroup.weekdays
+ = f.input :task_name
+ = f.input :task_required_users
+ = f.input :task_duration, :as => :select, :collection => (1..3)
+ = f.input :task_description, as: :text, input_html: {rows: 5}
+ = f.input :next_weekly_tasks_number
+
+= f.input :user_tokens, :as => :string,
+ :input_html => { 'data-pre' => f.object.users.map { |u| u.token_attributes }.to_json }
+
+- content_for :javascript do
+ :javascript
+ function toggleWeeklyTaskFields() {
+ if ($('#workgroup_weekly_task').is(':checked')) {
+ $('#weekly_task_fields .control-group').show();
+ $('#weekly_task_fields input').removeAttr('disabled');
+ } else {
+ $('#weekly_task_fields .control-group').hide();
+ $('#weekly_task_fields input').attr('disabled', 'disabled');
+ }
+ }
+
+ $(function() {
+ toggleWeeklyTaskFields();
+ $('#workgroup_weekly_task').click(function() {
+ toggleWeeklyTaskFields();
+ });
+
+ $("##{f.object.class.to_s.underscore}_user_tokens").tokenInput("#{users_path(:format => :json)}", {
+ crossDomain: false,
+ prePopulate: $("##{f.object.class.to_s.underscore}_user_tokens").data("pre"),
+ hintText: '#{t('.search_user')}',
+ noResultText: '#{t('.user_not_found')}',
+ searchingText: '#{t('.search')}',
+ theme: 'facebook'
+ });
+ });
+
diff --git a/app/views/shared/_loginInfo.haml b/app/views/shared/_loginInfo.haml
index 83e574a0..8ca136ec 100644
--- a/app/views/shared/_loginInfo.haml
+++ b/app/views/shared/_loginInfo.haml
@@ -1,10 +1,9 @@
%ul
%li
- = image_tag 'b_user.png' , :size => '7x10', :border => 0, :alt => "Profil"
- = link_to h(@current_user.nick), my_profile_path, { :title => "Profil bearbeiten" }
- - if Foodsoft.config[:homepage]
- %li= link_to Foodsoft.config[:name], Foodsoft.config[:homepage], { :title => _("Go to your FoodCoop-Hompage") }
- %li= link_to "Hilfe", 'http://dev.foodcoops.net/wiki/FoodsoftDoku'
- %li= link_to_remote "Feedback", :url => {:controller => "/feedback", :action => "new"}, |
- :method => :get, :html => {:title => "Fehler gefunden? Vorschlag? Idee? Kritik?"} |
- %li= link_to "Abmelden", logout_path
\ No newline at end of file
+ = image_tag 'b_user.png' , :size => '7x10', :border => 0, :alt => t('.profile')
+ = link_to h(@current_user.nick), my_profile_path, { :title => t('.edit_profile') }
+ - if FoodsoftConfig[:homepage]
+ %li= link_to FoodsoftConfig[:name], FoodsoftConfig[:homepage], { :title => t('.homepage_title') }
+ %li= link_to t('.help'), FoodsoftConfig[:help_url]
+ %li= link_to t('.feedback.title'), new_feedback_path, :title => t('.feedback.desc')
+ %li= link_to t('.logout'), logout_path
diff --git a/app/views/shared/_open_orders.html.haml b/app/views/shared/_open_orders.html.haml
index 618bd1fc..ebda2730 100644
--- a/app/views/shared/_open_orders.html.haml
+++ b/app/views/shared/_open_orders.html.haml
@@ -1,30 +1,33 @@
-.box_title
- %h2 Laufende Bestellungen
-.column_content
+%section
+ %h2= t '.title'
+ - if ordergroup.not_enough_apples?
+ .alert
+ = t '.not_enough_apples'
- unless Order.open.empty?
- %table.list
+ %table.table.table-striped
%thead
%tr
- %th Lieferantin
- %th Ende
- %th Wer hat bestellt?
- %th Summe
+ %th= t '.supplier'
+ %th= t '.ending'
+ %th= t '.who_ordered'
+ %th= t '.total'
%tbody
- total = 0
- Order.open.each do |order|
- %tr{:class => cycle('even', 'odd', :name => 'open_orders')}
- %td= link_to h(order.name), :controller => 'ordering', :action => 'order', :id => order
- %td=h format_time(order.ends) unless order.ends.nil?
- - if group_order = order.group_order(@ordergroup)
+ %tr
+ %td= link_to_ordering(order)
+ %td= format_time(order.ends) unless order.ends.nil?
+ - if group_order = order.group_order(ordergroup)
- total += group_order.price
- %td=h "#{group_order.updated_by.nick} (#{format_time(group_order.updated_on)})"
- %td= number_to_currency(group_order.price)
+ %td= "#{group_order.updated_by.nick} (#{format_time(group_order.updated_on)})"
+ %td.numeric= number_to_currency(group_order.price)
- else
- %td
- %td
- - if total > 0
- %p
- Gesamtsumme:
- %b= number_to_currency(total)
+ %td{:colspan => 2}
+ - if total > 0
+ %tfooter
+ %tr
+ %th(colspan="2")
+ %th= t('.total_sum') + ':'
+ %th.numeric= number_to_currency(total)
- else
- %i Derzeit gibt es keine laufenden Bestellungen
\ No newline at end of file
+ %i= t '.no_open_orders'
diff --git a/app/views/shared/_user_form.rhtml b/app/views/shared/_user_form.rhtml
deleted file mode 100644
index b265f464..00000000
--- a/app/views/shared/_user_form.rhtml
+++ /dev/null
@@ -1,46 +0,0 @@
-<%= @form.error_messages %>
-
-
-
- <%= @form.label :nick, "Benutzername" %>
- <%= @form.text_field :nick %>
-
-
- <%= @form.label :first_name, "Vorname" %>
- <%= @form.text_field :first_name %>
-
-
- <%= @form.label :last_name, "Nachname" %>
- <%= @form.text_field :last_name %>
-
-
- <%= @form.label :email, "E-Mail" %>
- <%= @form.text_field :email %>
-
-
- <%= @form.label :phone, "Telefon" %>
- <%= @form.text_field :phone %>
-
-
-
-
-
- <%= @form.label :password, "Passwort" %>
- <%= @form.password_field :password %>
-
-
- <%= @form.label :password_confirmation, "Passwort-Wiederholung" %>
- <%= @form.password_field :password_confirmation %>
-
-
-
-
- Einstellungen:
-
- <% for setting in User::setting_keys.keys -%>
-
- <%=h User::setting_keys[setting]%>
- <%= check_box_tag "user[setting_attributes][#{setting}]", '1', @user.settings[setting] == '1' || @user.settings_default(setting) %>
-
- <% end -%>
-
diff --git a/app/views/shared/_user_form_fields.html.haml b/app/views/shared/_user_form_fields.html.haml
new file mode 100644
index 00000000..fa11b393
--- /dev/null
+++ b/app/views/shared/_user_form_fields.html.haml
@@ -0,0 +1,15 @@
+= f.input :nick
+= f.input :first_name
+= f.input :last_name
+= f.input :email
+= f.input :phone
+= f.input :password, :required => f.object.new_record?
+= f.input :password_confirmation
+.control-group
+ .controls
+ - for setting in User::setting_keys.keys
+ %label.checkbox{:for => "user[setting_attributes][#{setting}]"}
+ = hidden_field_tag "user[setting_attributes][#{setting}]", '0'
+ = check_box_tag "user[setting_attributes][#{setting}]", '1',
+ f.object.settings[setting] == '1' || f.object.settings_default(setting)
+ = User::setting_keys[setting]
diff --git a/app/views/shared/_workgroup_members.haml b/app/views/shared/_workgroup_members.haml
index b6410ec7..960113d8 100644
--- a/app/views/shared/_workgroup_members.haml
+++ b/app/views/shared/_workgroup_members.haml
@@ -1,6 +1,14 @@
-- for group in Group.find :all, :conditions => "type != 'Ordergroup'"
- %h4= link_to_function group.name, "Element.toggle('workgroup_#{group.id}')"
- %ul{:style => "display:none"}[group]
- - for user in group.users.find :all, :order => "nick"
- %li= user.nick + " (#{user.ordergroup.name if user.ordergroup})"
-
\ No newline at end of file
+.well.well-small
+ %h4= t '.title'
+ #groupMembers.accordion
+ - Workgroup.all.each do |workgroup|
+ .accordion-group
+ .accoridon-heading
+ = link_to workgroup.name, "#collapse#{workgroup.id}", data: {toggle: 'collapse', parent: '#groupMembers'}
+ %div{id: "collapse#{workgroup.id}", class: 'accordion-body collapse'}
+ .accordion-inner
+ %ul.unstyled
+ - workgroup.users.includes(:groups).order('nick').each do |user|
+ %li
+ = user.nick
+ %small (#{user.ordergroup.try(:name)})
diff --git a/app/views/shared/memberships/_current_members.rhtml b/app/views/shared/memberships/_current_members.rhtml
index 6560e150..81aab3a0 100644
--- a/app/views/shared/memberships/_current_members.rhtml
+++ b/app/views/shared/memberships/_current_members.rhtml
@@ -9,7 +9,7 @@
<% for membership in memberships %>
<%= membership.user.nick %> (<%=h membership.user.first_name + ' ' + membership.user.last_name %>)
- | <%= link_to_remote 'entfernen',
+ | <%= link_to_remote t('.drop'),
:url => { :controller => '/memberships', :action => 'drop_member', :id => @group, :membership_id => membership },
:before => "Element.show('loader')",
:success => "Element.hide('loader')" %>
@@ -17,5 +17,5 @@
<% end %>
<% else %>
-<%= @group.name %> hat keine Mitglieder.
- <% end %>
\ No newline at end of file
+<%= t('.no_members', group: @group.name) %>
+ <% end %>
diff --git a/app/views/shared/memberships/_members.rhtml b/app/views/shared/memberships/_members.rhtml
index b3229860..55a35452 100644
--- a/app/views/shared/memberships/_members.rhtml
+++ b/app/views/shared/memberships/_members.rhtml
@@ -1,13 +1,10 @@
-Mitglieder von <%=h @group.name %>
+<%=h t('.title', group: @group.name) %>
-
- Hier kannst Du die Mitglieder der Gruppe verwalten oder ein neues Foodcoop-Mitglied in die Gruppe
- <%= remote_link_to('einladen', :url => new_invite_path(:id => @group)) %>.
-
+ <%= t('.desc', link: remote_link_to(t('.invite'), :url => new_invite_path(:id => @group))).html_safe %>
-
Sind schon Mitglieder
+ <%= t('.already_members') %>
<%=render :partial => 'shared/memberships/current_members' %>
@@ -15,11 +12,11 @@
-
Sind noch keine Mitglieder
+ <%= t('.no_members_yet') %>
<%= render :partial => 'shared/memberships/non_members' %>
- <%= remote_link_to('Person einladen', :url => new_invite_path(:id => @group)) %>
+ <%= remote_link_to(t('.invite_someone'), :url => new_invite_path(:id => @group)) %>
diff --git a/app/views/shared/memberships/_non_members.rhtml b/app/views/shared/memberships/_non_members.rhtml
index e96b2d89..2e177bc2 100644
--- a/app/views/shared/memberships/_non_members.rhtml
+++ b/app/views/shared/memberships/_non_members.rhtml
@@ -2,10 +2,10 @@
<% for user in @group.non_members %>
<%= user.nick %> (<%=h user.first_name + ' ' + user.last_name %>)
- | <%= link_to_remote 'hinzufügen',
+ | <%= link_to_remote t('.add'),
:url => { :controller => '/memberships', :action => 'add_member', :id => @group, :user_id => user },
:before => "Element.show('loader')",
:success => "Element.hide('loader')" %>
<% end %>
-
\ No newline at end of file
+
diff --git a/app/views/stock_takings/_stock_article_form.html.haml b/app/views/stock_takings/_stock_article_form.html.haml
index a1f05557..99898b1a 100644
--- a/app/views/stock_takings/_stock_article_form.html.haml
+++ b/app/views/stock_takings/_stock_article_form.html.haml
@@ -1,35 +1,10 @@
-- remote_form_for stock_article, :url => add_stock_article_stock_takings_path do |form|
- = form.error_messages
- %p
- Lieferantin
- %br/
- = form.select :supplier_id, Supplier.without_deleted(:order => 'name').collect{ |s| [s.name, s.id] }
- %p
- Name
- %br/
- = form.text_field :name
- %p
- Einheit
- %br/
- = form.text_field :unit
- %p
- Notiz
- %br/
- = form.text_field :note
- %p
- Nettopreis
- %br/
- = form.text_field :price
- %p
- MwSt
- %br/
- = form.text_field :tax, :value => (stock_article.tax || 7.0)
- %p
- Pfand
- %br/
- = form.text_field :deposit
- %p
- Kategorie:
- = form.select :article_category_id, ArticleCategory.all(:order => 'name').collect { |c| [c.name, c.id] }
- %p
- = submit_tag "Lagerartikel hinzufügen"
\ No newline at end of file
+- simple_form_for stock_article, url: add_stock_article_stock_takings_path, remote: true do |f|
+ = f.association :supplier
+ = f.input :name
+ = f.input :unit
+ = f.input :note
+ = f.input :price
+ = f.input :tax
+ = f.input :deposit
+ = f.association :article_category
+ = f.submit
\ No newline at end of file
diff --git a/app/views/stock_takings/_stock_change.html.haml b/app/views/stock_takings/_stock_change.html.haml
index 1cb10164..616be369 100644
--- a/app/views/stock_takings/_stock_change.html.haml
+++ b/app/views/stock_takings/_stock_change.html.haml
@@ -1,9 +1,7 @@
%p
- - fields_for "stock_taking[stock_change_attributes][]", stock_change do |form|
- - article = stock_change.stock_article
-
+ = simple_fields_for "stock_taking[stock_change_attributes][]", stock_change do |form|
= form.hidden_field :stock_article_id
- = "Menge (#{article.quantity_available})"
- = form.text_field :quantity, :size => 5, :autocomplete => 'off'
- %b=h truncate(article.name)
- = "(#{number_to_currency(article.price)} / #{article.unit})"
+ = "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})"
diff --git a/app/views/stock_takings/_stock_takings.html.haml b/app/views/stock_takings/_stock_takings.html.haml
new file mode 100644
index 00000000..de06413c
--- /dev/null
+++ b/app/views/stock_takings/_stock_takings.html.haml
@@ -0,0 +1,19 @@
+- if StockTaking.count > 20
+ = items_per_page
+= pagination_links_remote @stock_takings
+
+%table.table.table-striped
+ %thead
+ %tr
+ %th= t '.date'
+ %th= t '.note'
+ %th
+ %tbody
+ - for stock_taking in @stock_takings
+ %tr
+ %td= link_to format_date(stock_taking.date), stock_taking
+ %td= truncate stock_taking.note
+ %td
+ = link_to t('ui.edit'), edit_stock_taking_path(stock_taking), class: 'btn btn-mini'
+ = link_to t('ui.delete'), stock_taking, :confirm => t('.confirm_delete'), :method => :delete,
+ class: 'btn btn-mini btn-danger'
diff --git a/app/views/stock_takings/edit.html.haml b/app/views/stock_takings/edit.html.haml
index 55e4ef73..09312f6e 100644
--- a/app/views/stock_takings/edit.html.haml
+++ b/app/views/stock_takings/edit.html.haml
@@ -1,16 +1,7 @@
-- title "Inventur bearbeiten"
+- title t('.title')
-- form_for(@stock_taking) do |f|
- = f.error_messages
- %p
- %b Datum
- %br/
- = f.date_select :date
- %p
- %b Notiz
- %br/
- = f.text_area :note, :size => "28x7"
- %p
- = f.submit "Invenur speichern"
- |
- = link_to "Abbrechen", stock_takings_path
\ No newline at end of file
+- simple_form_for(@stock_taking) do |f|
+ = f.input :date
+ = f.input :note
+ = f.submit
+ = link_to t('ui.cancel'), stock_takings_path
diff --git a/app/views/stock_takings/index.html.haml b/app/views/stock_takings/index.html.haml
index b02e2f3e..2717e615 100644
--- a/app/views/stock_takings/index.html.haml
+++ b/app/views/stock_takings/index.html.haml
@@ -1,25 +1,9 @@
-- title "Inventurübersicht"
+- title t('.title')
-%p
- = link_to "Neue Iniventur anlegen", new_stock_taking_path
- |
- = link_to "Lager", stock_articles_path
+.well.well-small
+ .btn-group
+ = link_to t('.new_inventory'), new_stock_taking_path, class: 'btn'
-%table.list{:style => "width:50em"}
- %thead
- %tr
- %th Datum
- %th Notiz
- %th
- %th
- %th
- %tbody
- - for stock_taking in @stock_takings
- %tr
- %td= link_to format_date(stock_taking.date), stock_taking
- %td=h truncate stock_taking.note
- %td= link_to 'Anzeigen', stock_taking
- %td= link_to 'Bearbeiten', edit_stock_taking_path(stock_taking)
- %td= link_to 'Löschen', stock_taking, :confirm => 'Are you sure?', :method => :delete
+#StockTakingsTable= render 'stock_takings'
diff --git a/app/views/stock_takings/index.js.haml b/app/views/stock_takings/index.js.haml
new file mode 100644
index 00000000..a485df34
--- /dev/null
+++ b/app/views/stock_takings/index.js.haml
@@ -0,0 +1 @@
+$('#StockTakingsTable').html('#{escape_javascript(render('stock_takings'))}');
\ No newline at end of file
diff --git a/app/views/stock_takings/new.html.haml b/app/views/stock_takings/new.html.haml
index c134e978..dfa9e03b 100644
--- a/app/views/stock_takings/new.html.haml
+++ b/app/views/stock_takings/new.html.haml
@@ -1,48 +1,17 @@
-- title "Neue Inventur anlegen"
+- title t('.title')
-.left_column{:style => "width:40em;"}
- - form_for(@stock_taking) do |f|
- .box_title
- %h2 Inventur anlegen
- .column_content
- = f.error_messages
- %p
- %b Datum
- %br/
- = f.date_select :date
- %p
- %b Notiz
- %br/
- = f.text_area :note, :size => "28x7", :value => "#{@current_user.nick}: ..."
- %h2 Lagerartikel
- %p
- %i
- Bitte trage hier alle gezählten Abweichungen vom
- = link_to "vorläufigen Lagerbestand", stock_articles_path
- ein. Bei Schwund benutze einfach ein Minus vor der Zahl.
- #stock_changes
- = render :partial => 'stock_change', :collection => @stock_taking.stock_changes
- %p
- = f.submit "Inventur anlegen"
- |
- = link_to "Abbrechen", stock_takings_path
+- content_for :sidebar do
+ %p
+ %i= t('.text_deviations', inv_link: link_to(t('.temp_inventory'), stock_articles_path)).html_safe
+ %p= t('.text_need_articles', create_link: link_to(t('.create'), new_stock_article_path)).html_safe
-.right_column{:style => "width:30em;"}
- .box_title
- %h2 Neuen Lagerartikel anlegen
- .column_content
- %p
- :javascript
- function fillNewStockArticle(text, li) {
- new Ajax.Updater('stock_article_form', '/stock_takings/fill_new_stock_article_form', {
- method: 'get',
- parameters: {article_id: li.id}
- });
- }
- Suche nach Artikeln aus dem allen Katalogen:
- = text_field_with_auto_complete :article, :name, {}, |
- {:url => {:controller => 'stockit', :action => 'auto_complete_for_article_name' }, |
- :after_update_element => 'fillNewStockArticle', :method => :get} |
- %hr/
- #stock_article_form
- = render :partial => 'stock_article_form', :locals => {:stock_article => StockArticle.new}
\ No newline at end of file
+= simple_form_for(@stock_taking) do |f|
+ = f.input :date, as: :date_picker
+ = f.input :note, :input_html => {:size => "28x7", :value => "#{@current_user.nick}: ..."}
+ %h2= t '.stock_articles'
+
+ #stock_changes
+ = render :partial => 'stock_change', :collection => @stock_taking.stock_changes
+ .form-actions
+ = f.submit class: 'btn'
+ = link_to t('ui.cancel'), stock_takings_path
diff --git a/app/views/stock_takings/show.html.haml b/app/views/stock_takings/show.html.haml
index ca17db78..2756bc14 100644
--- a/app/views/stock_takings/show.html.haml
+++ b/app/views/stock_takings/show.html.haml
@@ -1,29 +1,27 @@
-- title "Inventur anzeigen"
+- title t('.title')
-%p
- Datum:
- = format_date @stock_taking.date
-%p
- Notiz:
- = simple_format @stock_taking.note
+.well.well-small
+ %dl.dl-horizontal
+ %dt= t '.date'
+ %dd= format_date @stock_taking.date
+ %dt= t '.note'
+ %dd= simple_format @stock_taking.note
-%h2 Artikel
-%table.list{:style => "width:30em"}
+%table.table.table-striped
%tr
- %th Artikel
- %th Lieferantin
- %th Einheit
- %th Menge
- - for stock_change in @stock_taking.stock_changes.all :include => :stock_article
+ %th= t '.article'
+ %th= t '.supplier'
+ %th= t '.unit'
+ %th= t '.amount'
+ - for stock_change in @stock_taking.stock_changes.all
%tr
%td= stock_change.stock_article.name
%td= stock_change.stock_article.supplier.name
%td= stock_change.stock_article.unit
%td= stock_change.quantity
-%br/
-= link_to "Bearbeiten", edit_stock_taking_path(@stock_taking)
-|
-= link_to "Inventurübersicht", stock_takings_path
-|
-= link_to "Löschen", @stock_taking, :method => :delete, :confirm => "Willst Du wirklich die Inventur löschen?"
\ No newline at end of file
+.btn-group
+ = link_to t('ui.edit'), edit_stock_taking_path(@stock_taking), class: 'btn'
+ = link_to t('.overview'), stock_takings_path, class: 'btn'
+ = link_to t('ui.delete'), @stock_taking, :method => :delete, :confirm => t('.confirm_delete'),
+ class: 'btn btn-danger'
diff --git a/app/views/stockit/_destroy_fail.js.haml b/app/views/stockit/_destroy_fail.js.haml
new file mode 100644
index 00000000..ca85c67c
--- /dev/null
+++ b/app/views/stockit/_destroy_fail.js.haml
@@ -0,0 +1,5 @@
+-# please polish the following line if you know how, same in view destroy
+var errorDiv = $('
');
+
+errorDiv.append(document.createTextNode('#{j(fail_msg)}'));
+$('div.container-fluid').prepend(errorDiv);
diff --git a/app/views/stockit/_form.html.haml b/app/views/stockit/_form.html.haml
index 62cf2e9d..7f489d04 100644
--- a/app/views/stockit/_form.html.haml
+++ b/app/views/stockit/_form.html.haml
@@ -1,44 +1,16 @@
-- form_for stock_article do |form|
- = form.error_messages
- %p
- Lieferantin
- %br/
- = form.select :supplier_id, Supplier.without_deleted(:order => 'name').collect{ |s| [s.name, s.id] }
- %p
- Name
- %br/
- = form.text_field :name
- %p
- Einheit
- %br/
- = form.text_field :unit
- %p
- Notiz
- %br/
- = form.text_field :note
+= simple_form_for stock_article, :validate => true do |f|
+ = f.association :supplier
+ = f.input :name
+ = f.input :unit
+ = f.input :note
+
- if stock_article.new_record?
- %p
- Nettopreis
- %br/
- = form.text_field :price
- %p
- MwSt
- %br/
- = form.text_field :tax, :value => (stock_article.tax || 7.0)
- %p
- Pfand
- %br/
- = form.text_field :deposit
+ = f.input :price
+ = f.input :tax
+ = f.input :deposit
- else
- %p
- Preis:
- %br/
- Um Chaos zu vermeiden können bis auf weiteres die Preise von angelegten
- Lagerartikeln nicht mehr verändert werden.
- %p
- Kategorie:
- = form.select :article_category_id, ArticleCategory.all(:order => 'name').collect { |c| [c.name, c.id] }
- %p
- = submit_tag "Lagerartikel speichern"
- |
- = link_to "Abbrechen", stock_articles_path
\ No newline at end of file
+ = f.input :price, :input_html => {:disabled => 'disabled'}, :hint => t('.form.price_hint')
+ = f.association :article_category
+ .form-actions
+ = f.submit class: 'btn'
+ = link_to t('ui.or_cancel'), stock_articles_path
diff --git a/app/views/stockit/destroy.js.haml b/app/views/stockit/destroy.js.haml
new file mode 100644
index 00000000..b70b44ca
--- /dev/null
+++ b/app/views/stockit/destroy.js.haml
@@ -0,0 +1,14 @@
+-# please polish the following line if you know how, same in partial _destroy_fail
+var successDiv = $('
');
+
+successDiv.append(document.createTextNode('#{escape_javascript(t('.notice', name: @article.name))}'));
+$('div.container-fluid').prepend(successDiv);
+
+-# WARNING: If you try to use the escape j(...) here, an error occurs:
+-# Ein Fehler ist aufgetreten: undefined method `gsub' for 50:Fixnum
+-# However, it should work without without escaping.
+-# Note that article names which are purely numeric, e.g. 12345, are escaped correctly (see above).
+
+$('#stockArticle-#{@article.id}').remove();
+
+-# WARNING: Do not use a simple .fadeOut() above, because it conflicts with the show/hide function of unavailable articles.
diff --git a/app/views/stockit/edit.html.haml b/app/views/stockit/edit.html.haml
index e27bebf3..bdf498c6 100644
--- a/app/views/stockit/edit.html.haml
+++ b/app/views/stockit/edit.html.haml
@@ -1,3 +1,3 @@
-- title "Lagerartikel bearbeiten"
+- title t('.title')
-= render :partial => 'form', :locals => {:stock_article => @stock_article}
\ No newline at end of file
+= render :partial => 'form', :locals => {:stock_article => @stock_article}
diff --git a/app/views/stockit/index.html.haml b/app/views/stockit/index.html.haml
index 654e32c5..777bb4b1 100644
--- a/app/views/stockit/index.html.haml
+++ b/app/views/stockit/index.html.haml
@@ -1,72 +1,67 @@
-- title "Lagerübersicht: #{StockArticle.available.count} Artikel im Lager"
+- title "Lager (#{StockArticle.available.count})"
+- content_for :javascript do
+ :javascript
+ $(function() {
+ $('tr.unavailable').hide();
+ })
-.menu
- - form_tag do
- %ul
- %li
- Ansichtsoptionen
- %ul
- %li= link_to_function "Nicht verfügbare Artikel zeigen/verstecken", |
- "$$('tr.unavailable').invoke('toggleClassName', 'hidden');", :style => "width:15em" |
+.well.well-small
+ .btn-toolbar
+ .btn-group.pull-right
+ = link_to '#', data: {toggle: 'dropdown'}, class: 'btn dropdown-toggle' do
+ = t '.view_options'
+ %span.caret
+ %ul.dropdown-menu
+ %li= link_to t('.toggle_unavailable'), "#", 'data-toggle-this' => 'tr.unavailable', tabindex: -1
+ .btn-group
+ = link_to_if @current_user.role_orders?, t('.order_online'), new_order_path(supplier_id: 0),
+ class: 'btn', class: 'btn btn-primary'
+ = link_to t('.new_stock_article'), new_stock_article_path, class: 'btn'
+ = link_to t('.new_stock_taking'), new_stock_taking_path, class: 'btn'
+ = link_to t('.show_stock_takings'), stock_takings_path, class: 'btn'
-%div{:style => "padding:0 0 0.5em 0.7em;margin-bottom:2em"}
- %span{:style => "float:left"}
- - form_tag do
- Neue Lieferung anlegen für:
- = select_tag :new_delivery, |
- options_for_select([[" -- Lieferantin wählen --", ""]] + |
- Supplier.without_deleted.collect {|s| [ s.name, url_for(new_supplier_delivery_path(s))] }), |
- :onchange => "redirectTo(this)", :style => "font-size: 0.9em;margin-left:1em;" |
+ .btn-group
+ = link_to '#', data: {toggle: 'dropdown'}, class: 'btn dropdown-toggle' do
+ = t '.new_delivery'
+ %span.caret
+ %ul.dropdown-menu
+ - Supplier.all.each do |supplier|
+ %li= link_to supplier.name, new_supplier_delivery_path(supplier), tabindex: -1
-.single_column{:style => 'width:100%; clear:both'}
- .box_title
- .column_content
- #actions
- %b= link_to "Neuen Lagerartikel anlegen", new_stock_article_path
- |
- = link_to_if @current_user.role_orders?, "Lagerbestellung online stellen", {:controller => 'orders', :action => 'new', :supplier_id => 0}
- |
- %b= link_to "Inventur anlegen", new_stock_taking_path
- |
- = link_to "Inventurübersicht", stock_takings_path
-
- #articles{:style => "clear:both;margin-top:1em"}
- %table.list
- %thead
- %tr
- %th Artikel
- %th im Lager
- %th davon bestellt
- %th verfügbar
- %th Einheit
- %th Preis
- %th MwSt
- %th Lieferantin
- %th Kategorie
- %th
- %tbody
- - for article in @stock_articles
- - class_name = cycle :even, :odd
- - class_name += " unavailable hidden" if article.quantity_available <= 0
- - class_name += " supplier_#{article.supplier.id}"
- %tr{:class => class_name}
- %td=h article.name
- %td= article.quantity
- %td= article.quantity - article.quantity_available
- %th= article.quantity_available
- %td= article.unit
- %td= article.price
- %td= number_to_percentage article.tax
- %td= link_to article.supplier.name, article.supplier
- %td= article.article_category.name
- %td
- = link_to icon(:edit), edit_stock_article_path(article)
- = link_to icon(:delete), article, :method => :delete, :confirm => "Bist Du sicher?"
- %p
- Aktueller Lagerwert:
- = number_to_currency StockArticle.stock_value
- |
- Artikelanzahl:
- = StockArticle.available.count
+%table.table.table-hover#articles
+ %thead
+ %tr
+ %th= t '.article.article'
+ %th= t '.article.stock'
+ %th= t '.article.ordered'
+ %th= t '.article.available'
+ %th= t '.article.unit'
+ %th= t '.article.price'
+ %th= t '.article.vat'
+ %th= t '.article.supplier'
+ %th= t '.article.category'
+ %th
+ %tbody
+ - for article in @stock_articles
+ %tr{:class => stock_article_classes(article), :id => "stockArticle-#{article.id}"}
+ %td=h article.name
+ %td= article.quantity
+ %td= article.quantity - article.quantity_available
+ %th= article.quantity_available
+ %td= article.unit
+ %td= article.price
+ %td= number_to_percentage article.tax
+ %td= link_to article.supplier.name, article.supplier
+ %td= article.article_category.name
+ %td
+ = link_to t('ui.edit'), edit_stock_article_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
+ = t '.stock_worth'
+ = number_to_currency StockArticle.stock_value
+ |
+ =t '.stock_count'
+ = StockArticle.available.count
diff --git a/app/views/stockit/new.html.haml b/app/views/stockit/new.html.haml
index 28177182..05609a84 100644
--- a/app/views/stockit/new.html.haml
+++ b/app/views/stockit/new.html.haml
@@ -1,16 +1,22 @@
-- title "Neuen Lagerartikel anlegen"
+- title t('.title')
-:javascript
- function fillNewStockArticle(text, li) {
- new Ajax.Updater('stock_article_form', '#{url_for(:controller => "stockit", :action => "fill_new_stock_article_form")}', {
- parameters: {article_id: li.id}
- });
- }
+- content_for :head do
+ :javascript
+ $(function() {
+ $('#article_search').autocomplete({
+ source: '#{articles_search_stock_articles_path}',
+ select: function(e, ui) {
+ alert(ui.item.value);
+ //location.href = '#{nil}' + ui.item.value;
+ }
+ });
+ })
-%p
- Suche nach Artikeln aus allen Katalogen:
- = text_field_with_auto_complete :article, :name, {}, |
- {:url => {:action => 'auto_complete_for_article_name'}, |
- :after_update_element => 'fillNewStockArticle'} |
+
+/
+ TODO: Fix this
+ %p
+ = t '.search_text'
+ = text_field_tag 'article_search'
#stock_article_form
- = render :partial => 'form', :locals => {:stock_article => @stock_article}
\ No newline at end of file
+ = render :partial => 'form', :locals => {:stock_article => @stock_article}
diff --git a/app/views/suppliers/_form.haml b/app/views/suppliers/_form.haml
index e3b3a2b7..09047bc1 100644
--- a/app/views/suppliers/_form.haml
+++ b/app/views/suppliers/_form.haml
@@ -1,60 +1,21 @@
-= error_messages_for 'supplier'
-
-- if @supplier.shared_supplier
- %p Lieferantin wird mit externer Datenbank verknüpft.
-.edit_form{:style=>"width:30em"}
- %table
- %tr
- %td
- %label{:for => "supplier_name"} Name
- %td= @f.text_field :name
- %tr
- %td
- %label{:for => "supplier_address"} Adresse
- %td= @f.text_field :address
- %tr
- %td
- %label{:for => "supplier_phone"} Telefon
- %td= @f.text_field :phone
- %tr
- %td
- %label{:for => "supplier_phone2"} Telefon2
- %td= @f.text_field :phone2
- %tr
- %td
- %label{:for => "supplier_fax"} Fax
- %td= @f.text_field :fax
- %tr
- %td
- %label{:for => "supplier_email"} E-Mail
- %td= @f.text_field :email
- %tr
- %td
- %label{:for => "supplier_url"} Hompage
- %td= @f.text_field :url
- %tr
- %td
- %label{:for => "supplier_contact_person"} Kotakt Person
- %td= @f.text_field :contact_person
- %tr
- %td
- %label{:for => "supplier_customer_number"} Kundennummer
- %td= @f.text_field :customer_number
- %tr
- %td
- %label{:for => "supplier_delivery_days"} Liefertage
- %td= @f.text_field :delivery_days
- %tr
- %td
- %label{:for => "supplier_order_howto"} BestellHowto
- %td= @f.text_field :order_howto
- %tr
- %td
- %label{:for => "supplier_note"} Notiz
- %td= @f.text_field :note
- %tr
- %td
- %label{:for => "supplier_min_order_quantity"} Mindestbestellmenge
- %td= @f.text_field :min_order_quantity
- = @f.hidden_field :shared_supplier_id
-
+= simple_form_for @supplier do |f|
+ - if @supplier.shared_supplier
+ .alert.alert-success
+ = t 'suppliers.shared_supplier_note'
+ = f.hidden_field :shared_supplier_id
+ = f.input :name
+ = f.input :address
+ = f.input :phone
+ = f.input :phone2
+ = f.input :fax
+ = f.input :email
+ = f.input :url
+ = f.input :contact_person
+ = f.input :customer_number
+ = f.input :delivery_days
+ = f.input :order_howto, as: :text, input_html: {rows: 5}
+ = f.input :note, as: :text, input_html: {rows: 5}
+ = f.input :min_order_quantity
+ .form-actions
+ = f.submit class: 'btn'
+ = link_to t('ui.or_cancel'), suppliers_path
diff --git a/app/views/suppliers/edit.haml b/app/views/suppliers/edit.haml
index 692f80dd..ea1ec870 100644
--- a/app/views/suppliers/edit.haml
+++ b/app/views/suppliers/edit.haml
@@ -1,6 +1,3 @@
-%h1 Lieferantin bearbeiten
-- form_for @supplier do |@f|
- = render :partial => 'form'
- = submit_tag 'Speichern'
- |
- = link_to 'Abbrechen', suppliers_path
\ No newline at end of file
+- title t('.title')
+
+= render "form"
diff --git a/app/views/suppliers/index.haml b/app/views/suppliers/index.haml
index cb3c5cf1..2ea9ad27 100644
--- a/app/views/suppliers/index.haml
+++ b/app/views/suppliers/index.haml
@@ -1,46 +1,27 @@
-- title "Artikeldatenbank"
+- title t('.title')
-.left_column{:style => "width:60%"}
- .box_title
- %h2 Lieferantinnen
- .column_content
- %p
- %i
- Erstelle eine
- = link_to 'neue Lieferantin', new_supplier_path
- oder
- = link_to 'importiere', shared_suppliers_suppliers_path
- aus der externen Artikeldatenbank.
- %table.list
- %thead
- %tr
- %th Name
- %th Telefon
- %th Kunden-Nr
- %th
- %th
- %th
- %tbody
- - for supplier in @suppliers
- %tr{:class => cycle('even','odd', :name => 'suppliers')}
- %td= link_to h(supplier.name) , supplier
- %td=h supplier.phone
- %td=h supplier.customer_number
- %td= link_to "Artikel (#{supplier.articles.without_deleted.count})", supplier_articles_path(supplier)
- %td= link_to "im Lager (#{supplier.stock_articles.without_deleted.count})", stock_articles_path
- %td= link_to "Lieferungen (#{supplier.deliveries.count})", supplier_deliveries_path(supplier)
-
-.right_column{:style => "width:37%"}
- .box_title
- %h2 Letzte Lieferungen
- .column_content
- %table
+- content_for :actionbar do
+ = link_to t('.action_new'), new_supplier_path, class: 'btn btn-primary'
+ = link_to t('.action_import'), shared_suppliers_suppliers_path, class: 'btn'
+%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
+ %th
+ %th
+ %tbody
+ - for supplier in @suppliers
%tr
- %th Datum
- %th Betrag
- %th Lieferantin
- - for delivery in @deliveries
- %tr
- %td= link_to delivery.delivered_on, [delivery.supplier, delivery]
- %td= link_to_invoice(delivery)
- %td=h delivery.supplier.name
\ No newline at end of file
+ %td= link_to h(supplier.name) , supplier
+ %td= supplier.phone
+ %td= supplier.customer_number
+ %td= link_to t('.articles', count: supplier.articles.undeleted.count), supplier_articles_path(supplier)
+ %td= link_to t('.stock', count: supplier.stock_articles.undeleted.count), stock_articles_path
+ %td= link_to t('.deliveries', count: supplier.deliveries.count), supplier_deliveries_path(supplier)
+ %td
+ = link_to t('ui.edit'), edit_supplier_path(supplier), class: 'btn btn-mini'
+ = link_to t('ui.delete'), supplier_path(supplier), method: :delete,
+ confirm: t('.confirm_del', name: supplier.name), class: 'btn btn-mini btn-danger'
diff --git a/app/views/suppliers/new.haml b/app/views/suppliers/new.haml
index c8a4d1a1..ea1ec870 100644
--- a/app/views/suppliers/new.haml
+++ b/app/views/suppliers/new.haml
@@ -1,7 +1,3 @@
-%h1 Neue Lieferantinn
-- form_for @supplier do |@f|
- = render :partial => 'form'
- = submit_tag "Speichern"
- |
- = link_to 'Abbrechen', suppliers_path
-
\ No newline at end of file
+- title t('.title')
+
+= render "form"
diff --git a/app/views/suppliers/shared_suppliers.haml b/app/views/suppliers/shared_suppliers.haml
index 53a0c948..6d36149c 100644
--- a/app/views/suppliers/shared_suppliers.haml
+++ b/app/views/suppliers/shared_suppliers.haml
@@ -1,27 +1,23 @@
-%h1 Externe Listen
-%p
- %i
- Hier werden die Lieferantinnen der externen Datenbank angezeigt.
- %br/
- Ihr könnt externe Lieferantinnen importieren, indem ihr sie einfach abonniert. (siehe unten)
- %br/
- Damit wird eine neue Lieferantin angelegt und mit der externen Datenbank verknüpft.
+- title t('.title')
+= t('.body').html_safe
-#shared_suppliers
- %i externe Lieferantinnen
- %table
+%table.table.table-striped
+ %thead
%tr
- %th Lieferantin
- %th Adresse
- %th Notiz
- %th Liefertag
- %th abonniert?
- %th
+ %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'
+ %tbody
- for shared_supplier in @shared_suppliers
- %tr{:class => cycle('even', 'odd', :name => "shared_suppliers")}
- %td=h shared_supplier.name
- %td=h shared_supplier.address
- %td=h shared_supplier.note
- %td=h shared_supplier.delivery_days
- %td= image_tag("icon_message.gif", :size => "16x16", :border => "0",:alt => "abonniert!") if shared_supplier.supplier
- %td= link_to "abonnieren", new_supplier_path(:shared_supplier_id => shared_supplier) unless shared_supplier.supplier
\ No newline at end of file
+ %tr
+ %td= shared_supplier.name
+ %td= shared_supplier.address
+ %td= shared_supplier.note
+ %td= shared_supplier.delivery_days
+ %td
+ - if shared_supplier.supplier
+ %i.icon-ok
+ - else
+ = link_to t('.subscribe'), new_supplier_path(:shared_supplier_id => shared_supplier), class: 'btn'
diff --git a/app/views/suppliers/show.haml b/app/views/suppliers/show.haml
index ec022344..0a9417fe 100644
--- a/app/views/suppliers/show.haml
+++ b/app/views/suppliers/show.haml
@@ -1,74 +1,55 @@
-- title "Lieferantin #{h(@supplier.name)}"
+- title @supplier.name
-.left_column{:style => "width:45%"}
- .box_title
- %h2=h @supplier.name
- .column_content
+.row-fluid
+ .span6
- if shared_supplier = @supplier.shared_supplier
- %p
- %strong Die Lieferantin ist mit der externen Artikledatenbank verknüpft.
+ .alert.alert-info
+ = t 'suppliers.shared_supplier_note'
- %table{:style => "width:40em"}
- %tr
- %td Adresse:
- %td{:style => "font-weight:bold"}=h @supplier.address
- %tr
- %td Telefon:
- %td{:style => "font-weight:bold"}=h @supplier.phone
- %tr
- %td Telefon2:
- %td{:style => "font-weight:bold"}=h @supplier.phone2
- %tr
- %td FAX:
- %td{:style => "font-weight:bold"}=h @supplier.fax
- %tr
- %td Email:
- %td{:style => "font-weight:bold"}=h @supplier.email
- %tr
- %td Hompage:
- %td{:style => "font-weight:bold"}=h @supplier.url
- %tr
- %td Kontakt-Person:
- %td{:style => "font-weight:bold"}=h @supplier.contact_person
- %tr
- %td Kundennummer:
- %td{:style => "font-weight:bold"}=h @supplier.customer_number
- %tr
- %td Liefertage:
- %td{:style => "font-weight:bold"}=h @supplier.delivery_days
- %tr
- %td BestellHowTo:
- %td{:style => "font-weight:bold"}=h @supplier.order_howto
- %tr
- %td Notiz:
- %td{:style => "font-weight:bold"}=h @supplier.note
- %tr
- %td Liefertage:
- %td{:style => "font-weight:bold"}=h @supplier.delivery_days
- %tr
- %td Mindestbestellmenge:
- %td{:style => "font-weight:bold"}=h @supplier.min_order_quantity
- %br/
+ %dl.dl-horizontal
+ %dt= t('simple_form.labels.supplier.address') + ':'
+ %dd= @supplier.address
+ %dt= t('simple_form.labels.supplier.phone') + ':'
+ %dd= @supplier.phone
+ %dt= t('simple_form.labels.supplier.phone2') + ':'
+ %dd= @supplier.phone2
+ %dt= t('simple_form.labels.supplier.fax') + ':'
+ %dd= @supplier.fax
+ %dt= t('simple_form.labels.supplier.email') + ':'
+ %dd= @supplier.email
+ %dt= t('simple_form.labels.supplier.url') + ':'
+ %dd= link_to @supplier.url, @supplier.url
+ %dt= t('simple_form.labels.supplier.contact_person') + ':'
+ %dd= @supplier.contact_person
+ %dt= t('simple_form.labels.supplier.customer_number') + ':'
+ %dd= @supplier.customer_number
+ %dt= t('simple_form.labels.supplier.delivery_days') + ':'
+ %dd= @supplier.delivery_days
+ %dt= t('simple_form.labels.supplier.order_howto') + ':'
+ %dd= @supplier.order_howto
+ %dt= t('simple_form.labels.supplier.note') + ':'
+ %dd= @supplier.note
+ %dt= t('simple_form.labels.supplier.min_order_quantity') + ':'
+ %dd= @supplier.min_order_quantity
+
+ .clearfix
- if @current_user.role_suppliers?
- = link_to 'Bearbeiten', edit_supplier_path(@supplier)
- |
- = link_to 'Löschen', @supplier, :confirm => 'Bist Du sicher?', :method => :delete
- |
- = link_to 'zurück', suppliers_path
+ .form-actions
+ = link_to t('ui.edit'), edit_supplier_path(@supplier), class: 'btn'
+ = link_to t('ui.delete'), @supplier, :confirm => t('.confirm_delete'), :method => :delete, class: 'btn btn-danger'
-.right_column{:style => "width:45%"}
- .box_title
- %h2 Letzte Lieferungen
- .column_content
- %table
- %tr
- %th Datum
- %th Betrag
- - for delivery in @deliveries
+ .span6
+ %h2= t '.last_deliveries'
+ %table.table.table-horizontal
+ %thead
%tr
- %td= link_to delivery.delivered_on, [@supplier, delivery]
- %td= link_to_invoice(delivery)
- %p
- = link_to "Neue Lieferung anlegen", new_supplier_delivery_path(@supplier)
- |
- = link_to "Zeige alle Lieferungen", supplier_deliveries_path(@supplier)
\ No newline at end of file
+ %th= t 'simple_form.labels.defaults.date'
+ %th= t 'simple_form.labels.defaults.amount'
+ %tbody
+ - for delivery in @deliveries
+ %tr
+ %td= link_to delivery.delivered_on, [@supplier, delivery]
+ %td= link_to_invoice(delivery)
+ .form-actions
+ = link_to t('.new_delivery'), new_supplier_delivery_path(@supplier), class: 'btn'
+ = link_to t('.show_deliveries'), supplier_deliveries_path(@supplier)
diff --git a/app/views/tasks/_archive_tasks.html.haml b/app/views/tasks/_archive_tasks.html.haml
new file mode 100644
index 00000000..46250ddd
--- /dev/null
+++ b/app/views/tasks/_archive_tasks.html.haml
@@ -0,0 +1,17 @@
+- if Task.done.count > 20
+ = items_per_page
+= pagination_links_remote @tasks
+
+%table.table.table-striped
+ %thead
+ %tr
+ %th= t '.due_date'
+ %th= t '.task'
+ %th= t '.who'
+ %th
+ %tbody
+ - @tasks.each do |task|
+ %tr
+ %td= task.due_date unless task.due_date.nil?
+ %td= link_to t('.task_format', name: task.name, duration: task.duration), :controller => "tasks", :action => "show", :id => task
+ %td= task_assignments task
diff --git a/app/views/tasks/_assignments.haml b/app/views/tasks/_assignments.haml
deleted file mode 100644
index d51671fd..00000000
--- a/app/views/tasks/_assignments.haml
+++ /dev/null
@@ -1,5 +0,0 @@
-- @task.assignments.each do |ass|
- = ass.user.nick
- %small= link_to icon(:delete, :title => "#{ass.user.nick} entfernen"), |
- {:action => "drop_assignment", :id => ass}, |
- :confirm => 'Bist du sicher?', :method => "post" |
diff --git a/app/views/tasks/_form.html.haml b/app/views/tasks/_form.html.haml
index e20985c0..3878f89f 100644
--- a/app/views/tasks/_form.html.haml
+++ b/app/views/tasks/_form.html.haml
@@ -1,36 +1,29 @@
-= form.error_messages
-= form.hidden_field :weekly
-%p
- %b Name
- %br/
- = form.text_field :name
-%p
- %b Beschreibung
- %br/
- = form.text_area :description, :cols => 50, :rows => 10
-%p
- %b Dauer
- %small Wie lange dauert die Aufgabe, 1-3 Stunden
- %br/
- = form.select :duration, options_for_select(1..3, @task.duration)
-%p
- %b Verantwortliche
- %small Aufgaben können mehrere Verantwortliche haben
- /%br/
- /= render :partial => "assignments"
-%p
- %small Benutze Kommas um mehrere Benutzerinnen zu trennen
- %br/
- = text_field_with_auto_complete :task, :user_list, {}, {:tokens => ","}
-%p
- %b Wieviel Benutzerinnen werden insgesamt benötigt?
- %br/
- = form.text_field :required_users, :size => 3
-%p
- %b Arbeitsgruppe
- %br/
- = form.select :workgroup_id, Workgroup.all(:order => 'name').collect {|g| [ g.name, g.id ] }, { :include_blank => true }
-%p
- %b Fälligkeit
- %br/
- = form.date_select :due_date, :start_year => 2007, :include_blank => true
\ No newline at end of file
+- content_for :javascript do
+ :javascript
+ $(function() {
+ $("#task_user_list").tokenInput("#{users_path(:format => :json)}", {
+ crossDomain: false,
+ prePopulate: $("#task_user_list").data("pre"),
+ hintText: '#{escape_javascript(t('.search.hint'))}',
+ noResultText: '#{escape_javascript(t('.search.noresult'))}',
+ searchingText: '#{escape_javascript(t('.search.placeholder'))}',
+ theme: 'facebook'
+ });
+ });
+
+- content_for :sidebar do
+ = render "shared/workgroup_members"
+
+= simple_form_for @task do |f|
+ = f.hidden_field :current_user_id
+ = f.input :name
+ = f.input :description, as: :text, input_html: {rows: 10}
+ = f.input :duration, :as => :select, :collection => 1..3
+ = f.input :user_list, :as => :string, :input_html => { 'data-pre' => @task.users.map { |u| u.token_attributes }.to_json }
+ = f.input :required_users
+ = f.association :workgroup
+ = f.input :due_date, as: :date_picker
+ = f.input :done
+ .form-actions
+ = f.submit class: 'btn'
+ = link_to t('ui.or_cancel'), :back
diff --git a/app/views/tasks/_list.haml b/app/views/tasks/_list.haml
index 0eca1968..a0b2af22 100644
--- a/app/views/tasks/_list.haml
+++ b/app/views/tasks/_list.haml
@@ -1,33 +1,27 @@
-%table
- %tr
- %th Fälligkeit
- %th Betreff
- %th{:colspan => '2'}
- Wer machts?
- %small (Wie viele werden noch benötigt?)
- - for task in @tasks
- - done = task.done ? " done" : ""
- %tr{:class => cycle('even','odd', :name => "tasks") + done }
- %td= format_date(task.due_date) unless task.due_date.nil?
- %td= link_to "#{task.name} (#{task.duration}h)", task_path(task)
- %td
- - unless task.users.empty?
- - owner = Array.new
- - task.assignments.each do |ass|
- - if ass.accepted?
- - nick = "
#{ass.user.nick.to_s} "
- - else
- - nick = "
#{ass.user.nick.to_s} ? "
- - owner << nick
- = owner.join(", ")
- = highlighted_required_users task
- %td
- - unless task.is_accepted?(@current_user)
- %span{:style => "float:left"}= button_to "Aufgabe übernehmen", :controller => "tasks", :action => "accept", :id => task
- = button_to "Aufgabe ablehnen", :controller => "tasks", :action => "reject", :id => task if task.is_assigned?(@current_user)
- - else
- - form_for :task, :url => {:action => "update_status", :id => task} do |f|
- Erledigt?
- = f.check_box :done, {:onchange => "submit()", :title => "Die Aufgabe wandert in das Archiv"}
- = "Erledigt" if task.done
- - reset_cycle("tasks")
\ No newline at end of file
+%table.table.table-striped
+ %thead
+ %tr
+ %th= t '.due_date'
+ %th= t '.task'
+ %th{:colspan => '2'}
+ = t '.who'
+ %small= t '.who_hint'
+ %tbody
+ - tasks.each do |task|
+ - done = task.done ? " done" : ""
+ %tr{:class => done }
+ %td= format_date(task.due_date) unless task.due_date.nil?
+ %td= link_to t('.task_format', name: task.name, duration: task.duration), task_path(task)
+ %td
+ = task_assignments task
+ = highlighted_required_users task
+ %td
+ - if !task.is_accepted?(current_user)
+ = link_to t('.accept_task'), accept_task_path(task), method: :post, class: 'btn btn-small'
+ = link_to t('.reject_task'), reject_task_path(task), method: :post, class: 'btn btn-small' if task.is_assigned?(current_user)
+ - elsif !task.done
+ = link_to set_done_task_path(task), method: :post, class: 'btn btn-small',
+ title: t('.mark_done') do
+ %i.icon-ok= t '.done_q'
+ - else
+ %i.icon-ok= t '.done'
diff --git a/app/views/tasks/_nav.haml b/app/views/tasks/_nav.haml
index 24d8d263..8fec6188 100644
--- a/app/views/tasks/_nav.haml
+++ b/app/views/tasks/_nav.haml
@@ -1,19 +1,13 @@
-#start_nav{:style => "float:right"}
- %h2 Aufgabenmenü
- %ul
- %li
- Aktionen
- %ul
- %li= link_to "Neue Aufgabe erstellen", :action => "new"
- %li
- Seiten
- %ul
- %li= link_to "Meine Aufgaben", user_tasks_path
- %li= link_to "Alle Aufgaben", tasks_path
- %li= link_to "Erledigt Aufgaben (Archiv)", archive_tasks_path
+- content_for :actionbar do
+ = link_to t('.new_task'), new_task_path, class: 'btn btn-primary'
- %li
- Gruppenaufgaben
- %ul
- - for group in Workgroup.all
- %li= link_to group.name, :controller => 'tasks', :action => "workgroup", :id => group
\ No newline at end of file
+- content_for :sidebar do
+ .well.well-small
+ %ul.nav.nav-list
+ %li.nav-header Seiten
+ %li= link_to t('.my_tasks'), user_tasks_path
+ %li= link_to t('.all_tasks'), tasks_path
+ %li= link_to t('.archive'), archive_tasks_path
+ %li.nav-header= t '.group_tasks'
+ - for group in Workgroup.all
+ %li= link_to group.name, workgroup_tasks_path(workgroup_id: group.id)
diff --git a/app/views/tasks/archive.haml b/app/views/tasks/archive.haml
index 126cb879..d1847119 100644
--- a/app/views/tasks/archive.haml
+++ b/app/views/tasks/archive.haml
@@ -1,20 +1,4 @@
-- title "Aufgabenarchiv"
-= render :partial => "nav"
+- title t('.title')
+= render 'nav'
-= will_paginate @orders
-%br/
-%table{:style => "width: 76%"}
- %tr
- %th Fälligkeitsdatum
- %th Betreff
- %th Verantwortliche Menschen
- %th
- - for task in @tasks
- %tr{:class => cycle('even','odd')}
- %td= task.due_date unless task.due_date.nil?
- %td= link_to "#{task.name} (#{task.duration}h)", :controller => "tasks", :action => "show", :id => task
- %td
- - unless task.users.empty?
- = task.users.map(&:nick).join(", ")
-%p
- = link_to_top
\ No newline at end of file
+#tasks= render 'archive_tasks'
diff --git a/app/views/tasks/archive.js.haml b/app/views/tasks/archive.js.haml
new file mode 100644
index 00000000..ff02f99f
--- /dev/null
+++ b/app/views/tasks/archive.js.haml
@@ -0,0 +1 @@
+$('#tasks').html('#{escape_javascript(render("archive_tasks"))}');
diff --git a/app/views/tasks/edit.haml b/app/views/tasks/edit.haml
index 37ceda70..624324db 100644
--- a/app/views/tasks/edit.haml
+++ b/app/views/tasks/edit.haml
@@ -1,12 +1,3 @@
-- title "Aufgabe bearbeiten"
+- title t('.title')
-#form{:style => "float:left; width:39em"}
- - form_for @task do |form|
- = render :partial => 'form', :locals => {:form => form}
- = submit_tag "Speichern"
- |
- = link_to "Abbrechen", :action => "show", :id => @task
-#workgroup_members{:style => "padding-left:41em"}
- %h3 Mitglieder der Gruppe
- #list
- = render :partial => "shared/workgroup_members"
\ No newline at end of file
+= render 'form'
diff --git a/app/views/tasks/index.haml b/app/views/tasks/index.haml
index a203fb39..e8d7df44 100644
--- a/app/views/tasks/index.haml
+++ b/app/views/tasks/index.haml
@@ -1,21 +1,18 @@
-- title "Aufgabenübersicht"
-= render :partial => "nav"
+- title t('.title')
+= render 'nav'
- unless @non_group_tasks.empty?
- .left_column{:style => "width:75%"}
- - @tasks = @non_group_tasks
- .box_title
- %h2 Aufgaben für alle!
- .column_content
- = render :partial => "list"
+ %section
+ %h3= t '.title_non_group'
+ = render 'list', tasks: @non_group_tasks
-- for @group in @groups
- - @tasks = @group.open_tasks
- - unless @tasks.empty?
- .left_column{:style => "width:75%"}
- .box_title
- %h2= link_to @group.name, :action => 'workgroup', :id => @group
- .column_content
- = render :partial => "list"
- = link_to_top
\ No newline at end of file
+- for group in @groups
+ - tasks = group.open_tasks
+ - unless tasks.empty?
+ %section
+ %h3
+ = group.name
+ %small= link_to t('.show_group_tasks'), workgroup_tasks_path(group)
+ = render 'list', tasks: tasks
+ = link_to_top
diff --git a/app/views/tasks/new.haml b/app/views/tasks/new.haml
index e0dca81d..624324db 100644
--- a/app/views/tasks/new.haml
+++ b/app/views/tasks/new.haml
@@ -1,12 +1,3 @@
-- title "Neue Aufgabe erstellen"
+- title t('.title')
-#form{:style => "float:left; width:39em"}
- - form_for @task do |form|
- = render :partial => 'form', :locals => {:form => form}
- = submit_tag "Aufgabe erstellen"
-
-#workgroup_members{:style => "padding-left:41em"}
- %h3 Mitglieder der Arbeitsgruppen
- %i Klicke auf den Gruppennamen um die Mitglieder zu sehen
- #list
- = render :partial => "shared/workgroup_members"
+= render 'form'
diff --git a/app/views/tasks/show.haml b/app/views/tasks/show.haml
index c99e99c8..23b843c7 100644
--- a/app/views/tasks/show.haml
+++ b/app/views/tasks/show.haml
@@ -1,38 +1,31 @@
-- title "Aufgabe im Detail"
-= render :partial => "nav"
+- title t('.title')
+= render 'nav'
-#task{:style => 'width:70%'}
- %table
- %tr
- %td{:style => "width: 10em"} Name
- %td
- %b= @task.name
- %tr
- %td{:style => "vertical-align:top;"} Beschreibung
- %td= simple_format(@task.description)
- %tr
- %td Fälligkeitsdatum
- %td= format_date(@task.due_date)
- %tr
- %td Dauer in Stunden
- %td= @task.duration
- %tr
- %td Verantwortliche Menschen
- %td= render :partial => "assignments"
- %tr
- %td Arbeitsgruppe
- %td
- - if @task.workgroup
- = link_to @task.workgroup.name, :action => "workgroup", :id => @task.workgroup
-
- %tr
- %td{:colspan => "2"}
- %div{:style => "float:left"} Als erledigt markieren
- - form_for :task, :url => {:action => "update_status", :id => @task} do |f|
- = f.check_box :done, {:onchange => "submit()", :title => "Die Aufgabe wandert in das Archiv"}
-
-
- %p
- = link_to "Bearbeiten", edit_task_path(@task)
- |
- = link_to "Löschen", task_path(@task), :method => :delete, :confirm => "Die Aufgabe wirklich löschen?"
+%section
+ %dl.dl-horizontal
+ %dt= t 'simple_form.labels.task.name'
+ %dd= @task.name
+ - if @task.description.present?
+ %dt= t 'simple_form.labels.defaults.description'
+ %dd= simple_format(@task.description)
+ - if @task.due_date.present?
+ %dt= t '.due_date'
+ %dd= format_date(@task.due_date)
+ %dt= t 'simple_form.labels.task.duration'
+ %dd= t('.hours', count: @task.duration)
+ %dt= t 'simple_form.labels.task.user_list'
+ %dd= task_assignments(@task)
+ %dt= t 'simple_form.labels.task.workgroup'
+ %dd
+ - if @task.workgroup
+ = link_to @task.workgroup.name, workgroup_tasks_path(workgroup_id: @task.workgroup_id)
+%p
+ - if !@task.is_accepted?(current_user)
+ = link_to t('.accept_task'), accept_task_path(@task), method: :post, class: 'btn btn-success'
+ - if @task.is_assigned?(current_user)
+ = link_to t('.reject_task'), reject_task_path(@task), method: :post, class: 'btn'
+ - 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?",
+ class: 'btn btn-danger'
diff --git a/app/views/tasks/user.html.haml b/app/views/tasks/user.html.haml
index 52e2e1d1..fd13ce2a 100644
--- a/app/views/tasks/user.html.haml
+++ b/app/views/tasks/user.html.haml
@@ -1,27 +1,17 @@
- title "Meine Aufgaben"
-= render :partial => "nav"
+= render 'nav'
+
+- unless @unaccepted_tasks.empty?
+ %section
+ %h3= t '.title_open'
+ = render 'list', tasks: @unaccepted_tasks
+
+%section
+ %h3= t '.title_accepted'
+ - unless @accepted_tasks.empty?
+ = render 'list', tasks: @accepted_tasks
+ - else
+ = t('.more', tasks_link: link_to(t('.tasks_link'), tasks_path)).html_safe
+ %br/
+ = link_to_top
-- @tasks = @unaccepted_tasks
-- unless @tasks.empty?
- .left_column{:style => "width:75%"}
- .box_title
- %h2 Offene Aufgaben
- .column_content
- = render :partial => "list"
-
-
-.left_column{:style => "width:75%"}
- .box_title
- %h2 Anstehende Aufgaben
- .column_content
- - @tasks = @accepted_tasks
- - unless @tasks.empty?
- = render :partial => "list"
- - else
- Nichts zu tun?
- = link_to "Hier", :action => "index"
- gibt es bestimmt Arbeit.
- %br/
- = link_to_top
-
-
\ No newline at end of file
diff --git a/app/views/tasks/workgroup.haml b/app/views/tasks/workgroup.haml
index a3de1603..a5525d90 100644
--- a/app/views/tasks/workgroup.haml
+++ b/app/views/tasks/workgroup.haml
@@ -1,27 +1,20 @@
-%h1
- Aufgaben verwalten für
- = @group.name
-= render :partial => "nav"
+- title t('.title', workgroup: @group.name)
+= render 'nav'
-.left_column{:style => "width:45em"}
- .box_title
- %h2 Wöchentliche Aufgaben verwalten
- .column_content
- - if @group.weekly_task
- %p= "Jeden
#{weekday(@group.weekday)} hat diese Arbeitsgruppe folgenden Job:
#{@group.task_name} "
- %p Die Wochenaufgaben werden von der Foodsoft automatisch erstellt. Eintragen müsst Ihr Euch aber selber.
- - else
- Noch keine Wochenaufgaben angelegt.
- - if @current_user.member_of?(@group) or @current_user.role_admin?
- = link_to "Wochenaufgaben bearbeiten", edit_foodcoop_workgroup_path(@group)
+%section.well
+ %h3= t '.weekly.title'
+ - if @group.weekly_task
+ = t('.weekly.desc', weekday: weekday(@group.weekday), task: @group.task_name).html_safe
+ - else
+ = t('.weekly.empty').html_safe
-.left_column{:style => "width:75%"}
- .box_title
- %h2 Alle Aufgaben der Gruppe
- .column_content
- - @tasks = @group.open_tasks
- = render :partial => "list"
- %br/
- = link_to_top
+ - if @current_user.member_of?(@group) or @current_user.role_admin?
+ = link_to t('.weekly.edit'), edit_foodcoop_workgroup_path(@group), class: 'btn'
-
\ No newline at end of file
+%section
+ %h3= t '.title_all'
+ = render 'list', tasks: @group.open_tasks
+ %br/
+ = link_to_top
+
+
diff --git a/app/views/workgroups/edit.html.erb b/app/views/workgroups/edit.html.erb
deleted file mode 100644
index 59c4d480..00000000
--- a/app/views/workgroups/edit.html.erb
+++ /dev/null
@@ -1,88 +0,0 @@
-<% title "Edit Workgroup" %>
-
-<% form_for @workgroup do |f| %>
- <%= f.error_messages %>
-
- <%= f.label :type %>
- <%= f.text_field :type %>
-
-
- <%= f.label :name %>
- <%= f.text_field :name %>
-
-
- <%= f.label :description %>
- <%= f.text_field :description %>
-
-
- <%= f.label :account_balance %>
- <%= f.text_field :account_balance %>
-
-
- <%= f.label :account_updated %>
- <%= f.datetime_select :account_updated %>
-
-
- <%= f.label :created_on %>
- <%= f.datetime_select :created_on %>
-
-
- <%= f.label :role_admin %>
- <%= f.check_box :role_admin %>
-
-
- <%= f.label :role_suppliers %>
- <%= f.check_box :role_suppliers %>
-
-
- <%= f.label :role_article_meta %>
- <%= f.check_box :role_article_meta %>
-
-
- <%= f.label :role_finance %>
- <%= f.check_box :role_finance %>
-
-
- <%= f.label :role_orders %>
- <%= f.check_box :role_orders %>
-
-
- <%= f.label :weekly_task %>
- <%= f.check_box :weekly_task %>
-
-
- <%= f.label :weekday %>
- <%= f.text_field :weekday %>
-
-
- <%= f.label :task_name %>
- <%= f.text_field :task_name %>
-
-
- <%= f.label :task_description %>
- <%= f.text_field :task_description %>
-
-
- <%= f.label :task_required_users %>
- <%= f.text_field :task_required_users %>
-
-
- <%= f.label :deleted_at %>
- <%= f.datetime_select :deleted_at %>
-
-
- <%= f.label :contact_person %>
- <%= f.text_field :contact_person %>
-
-
- <%= f.label :contact_phone %>
- <%= f.text_field :contact_phone %>
-
-
- <%= f.label :contact_address %>
- <%= f.text_field :contact_address %>
-
-
<%= f.submit "Submit" %>
-<% end %>
-
-
diff --git a/app/views/workgroups/edit.html.haml b/app/views/workgroups/edit.html.haml
new file mode 100644
index 00000000..9346430a
--- /dev/null
+++ b/app/views/workgroups/edit.html.haml
@@ -0,0 +1,84 @@
+- title t('.title')
+- form_for @workgroup do |f|
+ = f.error_messages
+ %p
+ = f.label :type
+ %br/
+ = f.text_field :type
+ %p
+ = f.label :name
+ %br/
+ = f.text_field :name
+ %p
+ = f.label :description
+ %br/
+ = f.text_field :description
+ %p
+ = f.label :account_balance
+ %br/
+ = f.text_field :account_balance
+ %p
+ = f.label :account_updated
+ %br/
+ = f.datetime_select :account_updated
+ %p
+ = f.label :created_on
+ %br/
+ = f.datetime_select :created_on
+ %p
+ = f.label :role_admin
+ %br/
+ = f.check_box :role_admin
+ %p
+ = f.label :role_suppliers
+ %br/
+ = f.check_box :role_suppliers
+ %p
+ = f.label :role_article_meta
+ %br/
+ = f.check_box :role_article_meta
+ %p
+ = f.label :role_finance
+ %br/
+ = f.check_box :role_finance
+ %p
+ = f.label :role_orders
+ %br/
+ = f.check_box :role_orders
+ %p
+ = f.label :weekly_task
+ %br/
+ = f.check_box :weekly_task
+ %p
+ = f.label :weekday
+ %br/
+ = f.text_field :weekday
+ %p
+ = f.label :task_name
+ %br/
+ = f.text_field :task_name
+ %p
+ = f.label :task_description
+ %br/
+ = f.text_field :task_description
+ %p
+ = f.label :task_required_users
+ %br/
+ = f.text_field :task_required_users
+ %p
+ = f.label :deleted_at
+ %br/
+ = f.datetime_select :deleted_at
+ %p
+ = f.label :contact_person
+ %br/
+ = f.text_field :contact_person
+ %p
+ = f.label :contact_phone
+ %br/
+ = f.text_field :contact_phone
+ %p
+ = f.label :contact_address
+ %br/
+ = f.text_field :contact_address
+ %p= f.submit t('ui.edit')
diff --git a/app/views/workgroups/index.html.erb b/app/views/workgroups/index.html.erb
deleted file mode 100644
index 1025a124..00000000
--- a/app/views/workgroups/index.html.erb
+++ /dev/null
@@ -1,52 +0,0 @@
-<% title "Workgroups" %>
-
-
-
- Type
- Name
- Description
- Account Balance
- Account Updated
- Created On
- Role Admin
- Role Suppliers
- Role Article Meta
- Role Finance
- Role Orders
- Weekly Task
- Weekday
- Task Name
- Task Description
- Task Required Users
- Deleted At
- Contact Person
- Contact Phone
- Contact Address
-
- <% for workgroup in @workgroups %>
-
- <%=h workgroup.type %>
- <%=h workgroup.name %>
- <%=h workgroup.description %>
- <%=h workgroup.account_balance %>
- <%=h workgroup.account_updated %>
- <%=h workgroup.created_on %>
- <%=h workgroup.role_admin %>
- <%=h workgroup.role_suppliers %>
- <%=h workgroup.role_article_meta %>
- <%=h workgroup.role_finance %>
- <%=h workgroup.role_orders %>
- <%=h workgroup.weekly_task %>
- <%=h workgroup.weekday %>
- <%=h workgroup.task_name %>
- <%=h workgroup.task_description %>
- <%=h workgroup.task_required_users %>
- <%=h workgroup.deleted_at %>
- <%=h workgroup.contact_person %>
- <%=h workgroup.contact_phone %>
- <%=h workgroup.contact_address %>
- <%= link_to "Edit", edit_workgroup_path(workgroup) %>
-
- <% end %>
-
-
diff --git a/app/views/workgroups/index.html.haml b/app/views/workgroups/index.html.haml
new file mode 100644
index 00000000..ab1ca879
--- /dev/null
+++ b/app/views/workgroups/index.html.haml
@@ -0,0 +1,46 @@
+- title t('.title')
+%table
+ %tr
+ %th Type
+ %th Name
+ %th Description
+ %th Account Balance
+ %th Account Updated
+ %th Created On
+ %th Role Admin
+ %th Role Suppliers
+ %th Role Article Meta
+ %th Role Finance
+ %th Role Orders
+ %th Weekly Task
+ %th Weekday
+ %th Task Name
+ %th Task Description
+ %th Task Required Users
+ %th Deleted At
+ %th Contact Person
+ %th Contact Phone
+ %th Contact Address
+ - for workgroup in @workgroups
+ %tr
+ %td= h workgroup.type
+ %td= h workgroup.name
+ %td= h workgroup.description
+ %td= h workgroup.account_balance
+ %td= h workgroup.account_updated
+ %td= h workgroup.created_on
+ %td= h workgroup.role_admin
+ %td= h workgroup.role_suppliers
+ %td= h workgroup.role_article_meta
+ %td= h workgroup.role_finance
+ %td= h workgroup.role_orders
+ %td= h workgroup.weekly_task
+ %td= h workgroup.weekday
+ %td= h workgroup.task_name
+ %td= h workgroup.task_description
+ %td= h workgroup.task_required_users
+ %td= h workgroup.deleted_at
+ %td= h workgroup.contact_person
+ %td= h workgroup.contact_phone
+ %td= h workgroup.contact_address
+ %td= link_to t('ui.edit'), edit_workgroup_path(workgroup)
diff --git a/app/workers/user_notifier.rb b/app/workers/user_notifier.rb
new file mode 100644
index 00000000..297ae978
--- /dev/null
+++ b/app/workers/user_notifier.rb
@@ -0,0 +1,43 @@
+# This plain ruby class should handle all user notifications, called by various models
+class UserNotifier
+ @queue = :foodsoft_notifier
+
+ # Resque style method to perform every class method defined here
+ def self.perform(foodcoop, method_name, *args)
+ FoodsoftConfig.select_foodcoop(foodcoop)
+ self.send method_name, args
+ end
+
+ def self.message_deliver(args)
+ message_id = args.first
+ Message.find(message_id).deliver
+ end
+
+ def self.finished_order(args)
+ order_id = args.first
+ Order.find(order_id).group_orders.each do |group_order|
+ group_order.ordergroup.users.each do |user|
+ begin
+ Mailer.order_result(user, group_order).deliver if user.settings["notify.orderFinished"] == '1'
+ rescue
+ Rails.logger.warn "Can't deliver mail to #{user.email}"
+ end
+ end
+ end
+ end
+
+ # If this order group's account balance is made negative by the given/last transaction,
+ # a message is sent to all users who have enabled notification.
+ def self.negative_balance(args)
+ ordergroup_id, transaction_id = args
+ transaction = FinancialTransaction.find transaction_id
+
+ Ordergroup.find(ordergroup_id).users.each do |user|
+ begin
+ Mailer.negative_balance(user, transaction).deliver if user.settings["notify.negativeBalance"] == '1'
+ rescue
+ Rails.logger.warn "Can't deliver mail to #{user.email}"
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/config.ru b/config.ru
new file mode 100644
index 00000000..fdb3d348
--- /dev/null
+++ b/config.ru
@@ -0,0 +1,4 @@
+# This file is used by Rack-based servers to start the application.
+
+require ::File.expand_path('../config/environment', __FILE__)
+run Foodsoft::Application
diff --git a/config/app_config.yml.SAMPLE b/config/app_config.yml.SAMPLE
index 700d114f..5977d5f9 100644
--- a/config/app_config.yml.SAMPLE
+++ b/config/app_config.yml.SAMPLE
@@ -1,10 +1,13 @@
# Foodsoft configuration
-development: &defaults
+default: &defaults
# If you wanna serve more than one foodcoop with one installation
# Don't forget to setup databases for each foodcoop. See also MULTI_COOP_INSTALL
multi_coop_install: false
+ # If multi_coop_install you have to use a coop name, which you you wanna be selected by default
+ default_scope: 'f'
+
# http config for this host
# Required for action mailer
protocol: http
@@ -26,7 +29,10 @@ development: &defaults
homepage: http://www.fctest.de
# foodsoft documentation URL
- help_url: http://foodsoft.fcschinke09.de/trac/wiki/FoodsoftDoku
+ help_url: https://github.com/bennibu/foodsoft/wiki/Doku
+
+ # documentation URL for the apples&pears work system
+ applepear_url: https://github.com/bennibu/foodsoft/wiki/%C3%84pfel-u.-Birnen
# price markup in percent
price_markup: 2.0
@@ -35,6 +41,10 @@ development: &defaults
# for total article price as long as the order is not finished.
tolerance_is_costly: false
+ # Ordergroups, which have less than 75 apples should not be allowed to make new orders
+ # Comment out this option to activate this restriction
+ # stop_ordering_under: 75
+
# email address to be used as sender
email_sender: foodsoft@myfoodcoop.org
@@ -51,7 +61,7 @@ development: &defaults
# Access to sharedLists, the external article-database
shared_lists:
- adapter: mysql
+ adapter: mysql2
host: localhost
database: sharedlists_development
username: root
@@ -75,8 +85,11 @@ development: &defaults
100g: 0.1
50g: 0.05
+development:
+ <<: *defaults
+
test:
<<: *defaults
production:
- <<: *defaults
\ No newline at end of file
+ <<: *defaults
diff --git a/config/application.rb b/config/application.rb
new file mode 100644
index 00000000..32ea295b
--- /dev/null
+++ b/config/application.rb
@@ -0,0 +1,65 @@
+require File.expand_path('../boot', __FILE__)
+
+require 'rails/all'
+
+if defined?(Bundler)
+ # If you precompile assets before deploying to production, use this line
+ Bundler.require(*Rails.groups(:assets => %w(development test)))
+ # If you want your assets lazily compiled in production, use this line
+ # Bundler.require(:default, :assets, Rails.env)
+end
+
+module Foodsoft
+ class Application < Rails::Application
+ # Settings in config/environments/* take precedence over those specified here.
+ # Application configuration should go into files in config/initializers
+ # -- all .rb files in that directory are automatically loaded.
+
+ # Custom directories with classes and modules you want to be autoloadable.
+ config.autoload_paths += %W(#{config.root}/lib)
+
+ # Only load the plugins named here, in the order given (default is alphabetical).
+ # :all can be used as a placeholder for all plugins not explicitly named.
+ # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
+
+ # Activate observers that should always be running.
+ # config.active_record.observers = :cacher, :garbage_collector, :forum_observer
+
+ # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
+ # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
+ # config.time_zone = 'Central Time (US & Canada)'
+
+ # Internationalization.
+ config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')]
+ config.i18n.default_locale = :de
+
+ # Configure the default encoding used in templates for Ruby 1.9.
+ config.encoding = "utf-8"
+
+ # Configure sensitive parameters which will be filtered from the log file.
+ config.filter_parameters += [:password]
+
+ # Enable escaping HTML in JSON.
+ config.active_support.escape_html_entities_in_json = true
+
+ # Use SQL instead of Active Record's schema dumper when creating the database.
+ # This is necessary if your schema can't be completely dumped by the schema dumper,
+ # like if you have constraints or database-specific column types
+ # config.active_record.schema_format = :sql
+
+ # Enforce whitelist mode for mass assignment.
+ # This will create an empty whitelist of attributes available for mass-assignment for all models
+ # in your app. As such, your models will need to explicitly whitelist or blacklist accessible
+ # parameters by using an attr_accessible or attr_protected declaration.
+ config.active_record.whitelist_attributes = false # TODO: Bette re-activate this!
+
+ # Enable the asset pipeline
+ config.assets.enabled = true
+
+ # 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
+ end
+end
diff --git a/config/boot.rb b/config/boot.rb
index d4242094..4489e586 100644
--- a/config/boot.rb
+++ b/config/boot.rb
@@ -1,129 +1,6 @@
-# Don't change this file!
-# Configure your app in config/environment.rb and config/environments/*.rb
+require 'rubygems'
-RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
+# Set up gems listed in the Gemfile.
+ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
-module Rails
- class << self
- def boot!
- unless booted?
- preinitialize
- pick_boot.run
- end
- end
-
- def booted?
- defined? Rails::Initializer
- end
-
- def pick_boot
- (vendor_rails? ? VendorBoot : GemBoot).new
- end
-
- def vendor_rails?
- File.exist?("#{RAILS_ROOT}/vendor/rails")
- end
-
- def preinitialize
- load(preinitializer_path) if File.exist?(preinitializer_path)
- end
-
- def preinitializer_path
- "#{RAILS_ROOT}/config/preinitializer.rb"
- end
- end
-
- class Boot
- def run
- load_initializer
- Rails::Initializer.run(:set_load_path)
- end
- end
-
- class VendorBoot < Boot
- def load_initializer
- require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"
- Rails::Initializer.run(:install_gem_spec_stubs)
- Rails::GemDependency.add_frozen_gem_path
- end
- end
-
- class GemBoot < Boot
- def load_initializer
- self.class.load_rubygems
- load_rails_gem
- require 'initializer'
- end
-
- def load_rails_gem
- if version = self.class.gem_version
- gem 'rails', version
- else
- gem 'rails'
- end
- rescue Gem::LoadError => load_error
- if load_error.message =~ /Could not find RubyGem rails/
- STDERR.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.)
- exit 1
- else
- raise
- end
- end
-
- class << self
- def rubygems_version
- Gem::RubyGemsVersion rescue nil
- end
-
- def gem_version
- if defined? RAILS_GEM_VERSION
- RAILS_GEM_VERSION
- elsif ENV.include?('RAILS_GEM_VERSION')
- ENV['RAILS_GEM_VERSION']
- else
- parse_gem_version(read_environment_rb)
- end
- end
-
- def load_rubygems
- min_version = '1.3.2'
- require 'rubygems'
- unless rubygems_version >= min_version
- $stderr.puts %Q(Rails requires RubyGems >= #{min_version} (you have #{rubygems_version}). Please `gem update --system` and try again.)
- exit 1
- end
-
- rescue LoadError
- $stderr.puts %Q(Rails requires RubyGems >= #{min_version}. Please install RubyGems and try again: http://rubygems.rubyforge.org)
- exit 1
- end
-
- def parse_gem_version(text)
- $1 if text =~ /^[^#]*RAILS_GEM_VERSION\s*=\s*["']([!~<>=]*\s*[\d.]+)["']/
- end
-
- private
- def read_environment_rb
- File.read("#{RAILS_ROOT}/config/environment.rb")
- end
- end
- end
-end
-
-# Bundler requirements
-class Rails::Boot
- def run
- load_initializer
-
- Rails::Initializer.class_eval do
- def load_gems
- @bundler_loaded ||= Bundler.require :default, Rails.env
- end
- end
-
- Rails::Initializer.run(:set_load_path)
- end
-end
-
-# All that for this:
-Rails.boot!
+require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
diff --git a/config/environment.rb b/config/environment.rb
index 97da71d1..39cacab4 100644
--- a/config/environment.rb
+++ b/config/environment.rb
@@ -1,70 +1,5 @@
-# Be sure to restart your web server when you modify this file.
+# Load the rails application
+require File.expand_path('../application', __FILE__)
-# Uncomment below to force Rails into production mode when
-# you don't control web/app server and can't set it the proper way
-# ENV['RAILS_ENV'] ||= 'production'
-
-# Specifies gem version of Rails to use when vendor/rails is not present
-RAILS_GEM_VERSION = '2.3.17' unless defined? RAILS_GEM_VERSION
-
-# Bootstrap the Rails environment, frameworks, and default configuration
-require File.join(File.dirname(__FILE__), 'boot')
-
-Rails::Initializer.run do |config|
- # Settings in config/environments/* take precedence over those specified here.
- # Application configuration should go into files in config/initializers
- # -- all .rb files in that directory are automatically loaded.
- # See Rails::Configuration for more options.
-
- # Skip frameworks you're not going to use (only works if using vendor/rails)
- # config.frameworks -= [ :action_web_service, :action_mailer ]
-
- # Only load the plugins named here, by default all plugins in vendor/plugins are loaded
- # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
-
- # Add additional load paths for your own custom dirs
- # config.load_paths += %W( #{RAILS_ROOT}/extras )
-
- # Force all environments to use the same logger level
- # (by default production uses :info, the others :debug)
- # config.log_level = :debug
-
- # Disable colorized logging output for ActiveRecord:
- config.active_record.colorize_logging = false
-
- # Use the database for sessions instead of the file system
- # (create the session table with 'rake db:sessions:create')
- # config.action_controller.session_store = :active_record_store
-
- # Use SQL instead of Active Record's schema dumper when creating the test database.
- # This is necessary if your schema can't be completely dumped by the schema dumper,
- # like if you have constraints or database-specific column types
- # config.active_record.schema_format = :sql
-
- # Activate observers that should always be running
- # config.active_record.observers = :cacher, :garbage_collector
-
- # Make Active Record use UTC-base instead of local time
- config.time_zone = 'Berlin'
-
- # Specify gems that this application depends on.
- # They can then be installed with "rake gems:install" on new installations.
- # You have to specify the :lib option for libraries, where the Gem name (sqlite3-ruby) differs from the file itself (sqlite3)
- # config.gem "bj"
- # config.gem "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net"
- # config.gem "sqlite3-ruby", :lib => "sqlite3"
- # config.gem "aws-s3", :lib => "aws/s3"
- #
- # config.gem "fastercsv"
- # config.gem "prawn", :version => '<=0.6.3'
- # config.gem "haml", :version => '>=2.0.6'
- # config.gem "routing-filter", :lib => "routing_filter"
-
- # The internationalization framework can be changed to have another default locale (standard is :en) or more load paths.
- # library for parsing/writing files from/to csv-file
- # All files from config/locales/*.rb,yml are added automatically.
- # config.i18n.load_path << Dir[File.join(RAILS_ROOT, 'my', 'locales', '*.{rb,yml}')]
- config.i18n.default_locale = :de
-
- # See Rails::Configuration for more options
-end
+# Initialize the rails application
+Foodsoft::Application.initialize!
diff --git a/config/environments/development.rb.SAMPLE b/config/environments/development.rb.SAMPLE
index 00d0d1fa..826028ba 100644
--- a/config/environments/development.rb.SAMPLE
+++ b/config/environments/development.rb.SAMPLE
@@ -1,33 +1,45 @@
-# Settings specified here will take precedence over those in config/environment.rb
+Foodsoft::Application.configure do
+ # Settings specified here will take precedence over those in config/application.rb
-# In the development environment your application's code is reloaded on
-# every request. This slows down response time but is perfect for development
-# since you don't have to restart the webserver when you make code changes.
-config.cache_classes = false
+ # In the development environment your application's code is reloaded on
+ # every request. This slows down response time but is perfect for development
+ # since you don't have to restart the web server when you make code changes.
+ config.cache_classes = false
-# Log error messages when you accidentally call methods on nil.
-config.whiny_nils = true
+ # Log error messages when you accidentally call methods on nil.
+ config.whiny_nils = true
-# Show full error reports and disable caching
-config.action_controller.consider_all_requests_local = true
-config.action_controller.perform_caching = false
-config.action_view.debug_rjs = true
+ # Show full error reports and disable caching
+ config.consider_all_requests_local = true
+ config.action_controller.perform_caching = false
-# Don't care if the mailer can't send
-config.action_mailer.raise_delivery_errors = false
+ # Don't care if the mailer can't send
+ config.action_mailer.raise_delivery_errors = false
-# Configure an SMTP server for email sending in development mode:
-# (cf. http://rails.rubyonrails.com/classes/ActionMailer/Base.html for info on options)
-config.action_mailer.smtp_settings = {
- :address => "smtp.your_host.de",
- :port => 25,
- :domain => "your-domain",
- :authentication => :login,
- :user_name => "username",
- :password => "secret"
-}
+ # Print deprecation notices to the Rails logger
+ config.active_support.deprecation = :log
-# Enable hirb for better console formatting
-require "hirb"
-Hirb.enable
-
\ No newline at end of file
+ # Only use best-standards-support built into browsers
+ config.action_dispatch.best_standards_support = :builtin
+
+ # Raise exception on mass assignment protection for Active Record models
+ config.active_record.mass_assignment_sanitizer = :strict
+
+ # Log the query plan for queries taking more than this (works
+ # with SQLite, MySQL, and PostgreSQL)
+ config.active_record.auto_explain_threshold_in_seconds = 0.5
+
+ # Do not compress assets
+ config.assets.compress = false
+
+ # Expands the lines which load the assets
+ config.assets.debug = true
+
+ # Configure hostname for action mailer
+ config.action_mailer.default_url_options = { host: 'localhost:3000' }
+
+ # Mailcatcher config, start mailcatcher from console with 'mailcatcher'
+ # Mailcatcher can be installed by gem install mailcatcher
+ config.action_mailer.delivery_method = :smtp
+ config.action_mailer.smtp_settings = { address: "localhost", port: 1025 }
+end
\ No newline at end of file
diff --git a/config/environments/production.rb b/config/environments/production.rb
index ce84c103..239640e0 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -1,25 +1,70 @@
-# Settings specified here will take precedence over those in config/environment.rb
+Foodsoft::Application.configure do
+ # Settings specified here will take precedence over those in config/application.rb
-# The production environment is meant for finished, "live" apps.
-# Code is not reloaded between requests
-config.cache_classes = true
+ # Code is not reloaded between requests
+ config.cache_classes = true
-# Enable threaded mode
-# config.threadsafe!
+ # Full error reports are disabled and caching is turned on
+ config.consider_all_requests_local = false
+ config.action_controller.perform_caching = true
-# Use a different logger for distributed setups
-# config.logger = SyslogLogger.new
-config.log_level = :warn
+ # Disable Rails's static asset server (Apache or nginx will already do this)
+ config.serve_static_assets = false
-# Full error reports are disabled and caching is turned on
-config.action_controller.consider_all_requests_local = false
-config.action_controller.perform_caching = true
+ # Compress JavaScripts and CSS
+ config.assets.compress = true
-# Use a different cache store in production
-# config.cache_store = :mem_cache_store
+ # Don't fallback to assets pipeline if a precompiled asset is missed
+ config.assets.compile = false
-# Enable serving of images, stylesheets, and javascripts from an asset server
-# config.action_controller.asset_host = "http://assets.example.com"
+ # Generate digests for assets URLs
+ config.assets.digest = true
-# Disable delivery errors if you bad email addresses should just be ignored
-# config.action_mailer.raise_delivery_errors = false
+ # # Defaults to nil and saved in location specified by config.assets.prefix
+ # config.assets.manifest = YOUR_PATH
+
+ # Specifies the header that your server uses for sending files
+ # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
+ # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
+
+ # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
+ config.force_ssl = true
+
+ # See everything in the log (default is :info)
+ # config.log_level = :debug
+
+ # Prepend all log lines with the following tags
+ # config.log_tags = [ :subdomain, :uuid ]
+
+ # Use a different logger for distributed setups
+ # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
+
+ # Use a different cache store in production
+ # config.cache_store = :mem_cache_store
+
+ # Enable serving of images, stylesheets, and JavaScripts from an asset server
+ # config.action_controller.asset_host = "http://assets.example.com"
+
+ # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
+ # config.assets.precompile += %w( search.js )
+
+ # Disable delivery errors, bad email addresses will be ignored
+ # config.action_mailer.raise_delivery_errors = false
+
+ # Enable threaded mode
+ # config.threadsafe!
+
+ # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
+ # the I18n.default_locale when a translation can not be found)
+ config.i18n.fallbacks = true
+
+ # Send deprecation notices to registered listeners
+ config.active_support.deprecation = :notify
+
+ # Log the query plan for queries taking more than this (works
+ # with SQLite, MySQL, and PostgreSQL)
+ # config.active_record.auto_explain_threshold_in_seconds = 0.5
+
+ # Use sendmail to avoid ssl cert problems
+ config.action_mailer.delivery_method = :sendmail
+end
diff --git a/config/environments/test.rb b/config/environments/test.rb
index f0689b92..30c06137 100644
--- a/config/environments/test.rb
+++ b/config/environments/test.rb
@@ -1,19 +1,37 @@
-# Settings specified here will take precedence over those in config/environment.rb
+Foodsoft::Application.configure do
+ # Settings specified here will take precedence over those in config/application.rb
-# The test environment is used exclusively to run your application's
-# test suite. You never need to work with it otherwise. Remember that
-# your test database is "scratch space" for the test suite and is wiped
-# and recreated between test runs. Don't rely on the data there!
-config.cache_classes = true
+ # The test environment is used exclusively to run your application's
+ # test suite. You never need to work with it otherwise. Remember that
+ # your test database is "scratch space" for the test suite and is wiped
+ # and recreated between test runs. Don't rely on the data there!
+ config.cache_classes = true
-# Log error messages when you accidentally call methods on nil.
-config.whiny_nils = true
+ # Configure static asset server for tests with Cache-Control for performance
+ config.serve_static_assets = true
+ config.static_cache_control = "public, max-age=3600"
-# Show full error reports and disable caching
-config.action_controller.consider_all_requests_local = true
-config.action_controller.perform_caching = false
+ # Log error messages when you accidentally call methods on nil
+ config.whiny_nils = true
-# Tell ActionMailer not to deliver emails to the real world.
-# The :test delivery method accumulates sent emails in the
-# ActionMailer::Base.deliveries array.
-config.action_mailer.delivery_method = :test
\ No newline at end of file
+ # Show full error reports and disable caching
+ config.consider_all_requests_local = true
+ config.action_controller.perform_caching = false
+
+ # Raise exceptions instead of rendering exception templates
+ config.action_dispatch.show_exceptions = false
+
+ # Disable request forgery protection in test environment
+ config.action_controller.allow_forgery_protection = false
+
+ # Tell Action Mailer not to deliver emails to the real world.
+ # The :test delivery method accumulates sent emails in the
+ # ActionMailer::Base.deliveries array.
+ config.action_mailer.delivery_method = :test
+
+ # Raise exception on mass assignment protection for Active Record models
+ config.active_record.mass_assignment_sanitizer = :strict
+
+ # Print deprecation notices to the stderr
+ config.active_support.deprecation = :stderr
+end
diff --git a/config/foodcoops.yml.SAMPLE b/config/foodcoops.yml.SAMPLE
deleted file mode 100644
index 2883d035..00000000
--- a/config/foodcoops.yml.SAMPLE
+++ /dev/null
@@ -1,45 +0,0 @@
-# Foodcoops configuration
-
-# test1 is the subdomain. e.g. test1.foodcoops.net
-test1:
- # name of this foodcoop
- name: FC Test
-
- # foodcoop contact information (used for FAX messages)
- contact:
- street: Grüne Straße 103
- zip_code: "10997"
- city: Berlin
- country: Deutschland
- email: foodsoft@myfoodcoop.org
- phone: "030 323 23249"
-
- # base URL for this installation
- base_url: http://www.fctest.de
-
- # foodsoft documentation URL
- help_url: http://foodsoft.fcschinke09.de/trac/wiki/FoodsoftDoku
-
- # price markup in percent
- price_markup: 2.0
-
- # email address to be used as sender
- email_sender: foodsoft@myfoodcoop.org
-
- # localized date/time formats
-
-
-
-#test2:
-# name: FC Test2
-# contact:
-# street: Grüne Straße 103
-# zip_code: "10997"
-# city: Berlin
-# country: Deutschland
-# email: foodsoft@fctest2.org
-# phone: "030 323 23249"
-# base_url: http://www.fctest2.de
-# help_url: http://foodsoft.fcschinke09.de/trac/wiki/FoodsoftDoku
-# price_markup: 1.0
-# email_sender: foodsoft@fctest2.org
diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb
new file mode 100644
index 00000000..59385cdf
--- /dev/null
+++ b/config/initializers/backtrace_silencers.rb
@@ -0,0 +1,7 @@
+# Be sure to restart your server when you modify this file.
+
+# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
+# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
+
+# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
+# Rails.backtrace_cleaner.remove_silencers!
diff --git a/config/initializers/bullet.rb b/config/initializers/bullet.rb
new file mode 100644
index 00000000..99e9a127
--- /dev/null
+++ b/config/initializers/bullet.rb
@@ -0,0 +1,6 @@
+if defined? Bullet
+ Bullet.enable = true
+ # Bullet.alert = true
+ Bullet.bullet_logger = true
+ Bullet.console = true
+end
\ No newline at end of file
diff --git a/config/initializers/client_side_validations.rb b/config/initializers/client_side_validations.rb
new file mode 100644
index 00000000..caf18378
--- /dev/null
+++ b/config/initializers/client_side_validations.rb
@@ -0,0 +1,14 @@
+# ClientSideValidations Initializer
+
+require 'client_side_validations/simple_form' if defined?(::SimpleForm)
+require 'client_side_validations/formtastic' if defined?(::Formtastic)
+
+# 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|
+# unless html_tag =~ /^
#{html_tag}#{instance.error_message.first} }.html_safe
+# else
+# %{#{html_tag}
}.html_safe
+# end
+# end
+
diff --git a/config/initializers/gettext_helper.rb b/config/initializers/gettext_helper.rb
deleted file mode 100644
index 50aabe6a..00000000
--- a/config/initializers/gettext_helper.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-# Remove this file, when every gettext-method <_("text to translate..")>
-# is replaced by rails L18n method: L18n.name.name...
-
-module ActionView
- class Base
- def _(text)
- text
- end
- end
-end
-
-module ActiveRecord
- class Base
- def _(text)
- text
- end
- end
-end
-
-module ActionController
- class Base
- def _(text)
- text
- end
- end
-end
diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb
index d531b8bb..c113bdc8 100644
--- a/config/initializers/inflections.rb
+++ b/config/initializers/inflections.rb
@@ -1,6 +1,6 @@
# Be sure to restart your server when you modify this file.
-# Add new inflection rules using the following format
+# Add new inflection rules using the following format
# (all these examples are active by default):
# ActiveSupport::Inflector.inflections do |inflect|
# inflect.plural /^(ox)$/i, '\1en'
@@ -8,3 +8,9 @@
# inflect.irregular 'person', 'people'
# inflect.uncountable %w( fish sheep )
# end
+#
+# These inflection rules are supported but not enabled by default:
+# ActiveSupport::Inflector.inflections do |inflect|
+# inflect.acronym 'RESTful'
+# end
+
diff --git a/config/initializers/load_app_config.rb b/config/initializers/load_app_config.rb
index 260dd278..1509536e 100644
--- a/config/initializers/load_app_config.rb
+++ b/config/initializers/load_app_config.rb
@@ -1,33 +1,26 @@
-# Loads and returns config and databases for selected foodcoop.
-# TODO: When to use class or module. It seems this could also be a Foodsoft-class?
-module Foodsoft
- mattr_accessor :env, :config, :database
- CONFIGS = YAML.load(File.read(RAILS_ROOT + "/config/app_config.yml"))
- DATABASES = YAML.load(File.read(RAILS_ROOT + "/config/database.yml"))
-
- class << self
- def env=(env)
- raise "No config or database for this environment (#{env}) available!" if CONFIGS[env].nil? or DATABASES[env].nil?
- @@config = CONFIGS[env].symbolize_keys
- @@database = DATABASES[env].symbolize_keys
- @@env = env
- end
- end
-end
# Initial load the default config and database from rails environment
-Foodsoft.env = RAILS_ENV
+# See config/app_config.yml for further details
+# Load Config, start by selecting defaults via current environment
+require 'foodsoft_config'
+FoodsoftConfig.init
# Set action mailer default host for url generating
url_options = {
- :host => Foodsoft.config[:host],
- :protocol => Foodsoft.config[:protocol]
+ :host => FoodsoftConfig[:host],
+ :protocol => FoodsoftConfig[:protocol]
}
-url_options.merge!({:port => Foodsoft.config[:port]}) if Foodsoft.config[:port]
-ActionMailer::Base.default_url_options = url_options
+url_options.merge!({:port => FoodsoftConfig[:port]}) if FoodsoftConfig[:port]
-# Configuration of the exception_notification plugin
-# Mailadresses are set in config/foodsoft.yaml
-ExceptionNotifier.exception_recipients = Foodsoft.config[:notification]['error_recipients']
-ExceptionNotifier.sender_address = Foodsoft.config[:notification]['sender_address']
-ExceptionNotifier.email_prefix = Foodsoft.config[:notification]['email_prefix']
+Foodsoft::Application.configure do
+ config.action_mailer.default_url_options = url_options
+
+ if Rails.env !~ /development|test/
+ # 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']
+ end
+end
diff --git a/config/initializers/secret_token.rb.SAMPLE b/config/initializers/secret_token.rb.SAMPLE
new file mode 100644
index 00000000..fcbd6c1e
--- /dev/null
+++ b/config/initializers/secret_token.rb.SAMPLE
@@ -0,0 +1,7 @@
+# Be sure to restart your server when you modify this file.
+
+# Your secret key for verifying the integrity of signed cookies.
+# If you change this key, all old signed cookies will become invalid!
+# Make sure the secret is at least 30 characters and all random,
+# no regular words or you'll be exposed to dictionary attacks.
+Foodsoft::Application.config.secret_token = '2be5574568ff4d270b108399078a8e485b363af84d441d02d2a6fd3fc51a8c015065790b7e414134e6d97ffc40da898a5a12f66f9de6b992b7ea96e7a34839b8'
diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb
new file mode 100644
index 00000000..c3ec8bf2
--- /dev/null
+++ b/config/initializers/session_store.rb
@@ -0,0 +1,8 @@
+# Be sure to restart your server when you modify this file.
+
+Foodsoft::Application.config.session_store :cookie_store, key: '_foodsoft_session'
+
+# Use the database for sessions instead of the cookie-based default,
+# which shouldn't be used to store highly confidential information
+# (create the session table with "rails generate session_migration")
+# Foodsoft::Application.config.session_store :active_record_store
diff --git a/config/initializers/session_store.rb.SAMPLE b/config/initializers/session_store.rb.SAMPLE
deleted file mode 100644
index 9d277335..00000000
--- a/config/initializers/session_store.rb.SAMPLE
+++ /dev/null
@@ -1,15 +0,0 @@
-# Be sure to restart your server when you modify this file.
-
-# Your secret key for verifying cookie session data integrity.
-# If you change this key, all old sessions will become invalid!
-# Make sure the secret is at least 30 characters and all random,
-# no regular words or you'll be exposed to dictionary attacks.
-ActionController::Base.session = {
- :key => '_foodsoft_session',
- :secret => 'as27ashi20867asdl27a9l2oa87dgh2o6a6s92l34las00121hha87072hla70072h097243hha092h4a'
-}
-
-# Use the database for sessions instead of the cookie-based default,
-# which shouldn't be used to store highly confidential information
-# (create the session table with "rake db:sessions:create")
-# ActionController::Base.session_store = :active_record_store
diff --git a/config/initializers/simple_form.rb b/config/initializers/simple_form.rb
new file mode 100644
index 00000000..b4cb19de
--- /dev/null
+++ b/config/initializers/simple_form.rb
@@ -0,0 +1,142 @@
+# Use this setup block to configure all options available in SimpleForm.
+SimpleForm.setup do |config|
+ # Wrappers are used by the form builder to generate a
+ # complete input. You can remove any component from the
+ # wrapper, change the order or even add your own to the
+ # stack. The options given below are used to wrap the
+ # whole input.
+ config.wrappers :default, :class => :input,
+ :hint_class => :field_with_hint, :error_class => :field_with_errors do |b|
+ ## Extensions enabled by default
+ # Any of these extensions can be disabled for a
+ # given input by passing: `f.input EXTENSION_NAME => false`.
+ # You can make any of these extensions optional by
+ # renaming `b.use` to `b.optional`.
+
+ # Determines whether to use HTML5 (:email, :url, ...)
+ # and required attributes
+ b.use :html5
+
+ # Calculates placeholders automatically from I18n
+ # You can also pass a string as f.input :placeholder => "Placeholder"
+ b.use :placeholder
+
+ ## Optional extensions
+ # They are disabled unless you pass `f.input EXTENSION_NAME => :lookup`
+ # to the input. If so, they will retrieve the values from the model
+ # if any exists. If you want to enable the lookup for any of those
+ # extensions by default, you can change `b.optional` to `b.use`.
+
+ # Calculates maxlength from length validations for string inputs
+ b.optional :maxlength
+
+ # Calculates pattern from format validations for string inputs
+ b.optional :pattern
+
+ # Calculates min and max from length validations for numeric inputs
+ b.optional :min_max
+
+ # Calculates readonly automatically from readonly attributes
+ b.optional :readonly
+
+ ## Inputs
+ b.use :label_input
+ b.use :hint, :wrap_with => { :tag => :span, :class => :hint }
+ b.use :error, :wrap_with => { :tag => :span, :class => :error }
+ end
+
+ # The default wrapper to be used by the FormBuilder.
+ config.default_wrapper = :default
+
+ # Define the way to render check boxes / radio buttons with labels.
+ # Defaults to :nested for bootstrap config.
+ # :inline => input + label
+ # :nested => label > input
+ config.boolean_style = :nested
+
+ # Default class for buttons
+ config.button_class = 'btn'
+
+ # Method used to tidy up errors. Specify any Rails Array method.
+ # :first lists the first message for each field.
+ # Use :to_sentence to list all errors for each field.
+ # config.error_method = :first
+
+ # Default tag used for error notification helper.
+ config.error_notification_tag = :div
+
+ # CSS class to add for error notification helper.
+ config.error_notification_class = 'alert alert-error'
+
+ # ID to add for error notification helper.
+ # config.error_notification_id = nil
+
+ # Series of attempts to detect a default label method for collection.
+ # config.collection_label_methods = [ :to_label, :name, :title, :to_s ]
+
+ # Series of attempts to detect a default value method for collection.
+ # config.collection_value_methods = [ :id, :to_s ]
+
+ # You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none.
+ # config.collection_wrapper_tag = nil
+
+ # You can define the class to use on all collection wrappers. Defaulting to none.
+ # config.collection_wrapper_class = nil
+
+ # You can wrap each item in a collection of radio/check boxes with a tag,
+ # defaulting to :span. Please note that when using :boolean_style = :nested,
+ # SimpleForm will force this option to be a label.
+ # config.item_wrapper_tag = :span
+
+ # You can define a class to use in all item wrappers. Defaulting to none.
+ # config.item_wrapper_class = nil
+
+ # How the label text should be generated altogether with the required text.
+ # config.label_text = lambda { |label, required| "#{required} #{label}" }
+
+ # You can define the class to use on all labels. Default is nil.
+ config.label_class = 'control-label'
+
+ # You can define the class to use on all forms. Default is simple_form.
+ config.form_class = 'form-horizontal'
+
+ # You can define which elements should obtain additional classes
+ # config.generate_additional_classes_for = [:wrapper, :label, :input]
+
+ # Whether attributes are required by default (or not). Default is true.
+ # config.required_by_default = true
+
+ # Tell browsers whether to use default HTML5 validations (novalidate option).
+ # Default is enabled.
+ config.browser_validations = true
+
+ # Collection of methods to detect if a file type was given.
+ # config.file_methods = [ :mounted_as, :file?, :public_filename ]
+
+ # Custom mappings for input types. This should be a hash containing a regexp
+ # to match as key, and the input type that will be used when the field name
+ # matches the regexp as value.
+ # config.input_mappings = { /count/ => :integer }
+
+ # Custom wrappers for input types. This should be a hash containing an input
+ # type as key and the wrapper that will be used for all inputs with specified type.
+ # config.wrapper_mappings = { :string => :prepend }
+
+ # Default priority for time_zone inputs.
+ # config.time_zone_priority = nil
+
+ # Default priority for country inputs.
+ # config.country_priority = nil
+
+ # Default size for text inputs.
+ # config.default_input_size = 50
+
+ # When false, do not use translations for labels.
+ # config.translate_labels = true
+
+ # Automatically discover new inputs in Rails' autoload path.
+ # config.inputs_discovery = true
+
+ # Cache SimpleForm inputs discovery
+ # config.cache_discovery = !Rails.env.development?
+end
diff --git a/config/initializers/simple_form_bootstrap.rb b/config/initializers/simple_form_bootstrap.rb
new file mode 100644
index 00000000..1a229676
--- /dev/null
+++ b/config/initializers/simple_form_bootstrap.rb
@@ -0,0 +1,45 @@
+# Use this setup block to configure all options available in SimpleForm.
+SimpleForm.setup do |config|
+ config.wrappers :bootstrap, :tag => 'div', :class => 'control-group', :error_class => 'error' do |b|
+ b.use :html5
+ b.use :placeholder
+ b.use :label
+ b.wrapper :tag => 'div', :class => 'controls' do |ba|
+ ba.use :input
+ ba.use :error, :wrap_with => { :tag => 'span', :class => 'help-inline' }
+ ba.use :hint, :wrap_with => { :tag => 'p', :class => 'help-block' }
+ end
+ end
+
+ config.wrappers :prepend, :tag => 'div', :class => "control-group", :error_class => 'error' do |b|
+ b.use :html5
+ b.use :placeholder
+ b.use :label
+ b.wrapper :tag => 'div', :class => 'controls' do |input|
+ input.wrapper :tag => 'div', :class => 'input-prepend' do |prepend|
+ prepend.use :input
+ end
+ input.use :hint, :wrap_with => { :tag => 'span', :class => 'help-block' }
+ input.use :error, :wrap_with => { :tag => 'span', :class => 'help-inline' }
+ end
+ end
+
+ config.wrappers :append, :tag => 'div', :class => "control-group", :error_class => 'error' do |b|
+ b.use :html5
+ b.use :placeholder
+ b.use :label
+ b.wrapper :tag => 'div', :class => 'controls' do |input|
+ input.wrapper :tag => 'div', :class => 'input-append' do |append|
+ append.use :input
+ end
+ input.use :hint, :wrap_with => { :tag => 'span', :class => 'help-block' }
+ input.use :error, :wrap_with => { :tag => 'span', :class => 'help-inline' }
+ end
+ end
+
+ # Wrappers for forms and inputs using the Twitter Bootstrap toolkit.
+ # Check the Bootstrap docs (http://twitter.github.com/bootstrap)
+ # to learn about the different styles for forms and inputs,
+ # buttons and other elements.
+ config.default_wrapper = :bootstrap
+end
diff --git a/config/initializers/wrap_parameters.rb b/config/initializers/wrap_parameters.rb
new file mode 100644
index 00000000..999df201
--- /dev/null
+++ b/config/initializers/wrap_parameters.rb
@@ -0,0 +1,14 @@
+# Be sure to restart your server when you modify this file.
+#
+# This file contains settings for ActionController::ParamsWrapper which
+# is enabled by default.
+
+# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
+ActiveSupport.on_load(:action_controller) do
+ wrap_parameters format: [:json]
+end
+
+# Disable root element in JSON by default.
+ActiveSupport.on_load(:active_record) do
+ self.include_root_in_json = false
+end
diff --git a/config/locales/de.yml b/config/locales/de.yml
deleted file mode 100644
index a32ac0db..00000000
--- a/config/locales/de.yml
+++ /dev/null
@@ -1,170 +0,0 @@
-de:
- home:
- index:
- title: Startseite
- date:
- formats:
- default: "%d.%m.%Y"
- short: "%e. %b"
- long: "%e. %B %Y"
- only_day: "%e"
-
- day_names: [Sonntag, Montag, Dienstag, Mittwoch, Donnerstag, Freitag, Samstag]
- abbr_day_names: [So, Mo, Di, Mi, Do, Fr, Sa]
- month_names: [~, Januar, Februar, März, April, Mai, Juni, Juli, August, September, Oktober, November, Dezember]
- abbr_month_names: [~, Jan, Feb, Mär, Apr, Mai, Jun, Jul, Aug, Sep, Okt, Nov, Dez]
- order: [ :day, :month, :year ]
-
- time:
- formats:
- default: "%A, %d. %B %Y, %H:%M Uhr"
- short: "%d. %B, %H:%M Uhr"
- long: "%A, %d. %B %Y, %H:%M Uhr"
- time: "%H:%M"
-
- am: "vormittags"
- pm: "nachmittags"
-
- datetime:
- distance_in_words:
- half_a_minute: 'eine halbe Minute'
- less_than_x_seconds:
- one: 'weniger als eine Sekunde'
- other: 'weniger als %{count} Sekunden'
- x_seconds:
- one: 'eine Sekunde'
- other: '%{count} Sekunden'
- less_than_x_minutes:
- one: 'weniger als eine Minute'
- other: 'weniger als %{count} Minuten'
- x_minutes:
- one: 'eine Minute'
- other: '%{count} Minuten'
- about_x_hours:
- one: 'etwa eine Stunde'
- other: 'etwa %{count} Stunden'
- x_days:
- one: 'ein Tag'
- other: '%{count} Tagen'
- about_x_months:
- one: 'etwa ein Monat'
- other: 'etwa %{count} Monaten'
- x_months:
- one: 'ein Monat'
- other: '%{count} Monaten'
- almost_x_years:
- one: 'fast ein Jahr'
- other: 'fast %{count} Jahre'
- about_x_years:
- one: 'etwa ein Jahr'
- other: 'etwa %{count} Jahren'
- over_x_years:
- one: 'mehr als ein Jahr'
- other: 'mehr als %{count} Jahren'
- prompts:
- second: "Sekunden"
- minute: "Minuten"
- hour: "Stunden"
- day: "Tag"
- month: "Monat"
- year: "Jahr"
-
- number:
- format:
- precision: 2
- separator: ','
- delimiter: '.'
- currency:
- format:
- unit: '€'
- format: '%n%u'
- separator:
- delimiter:
- precision:
- percentage:
- format:
- delimiter: ""
- precision:
- format:
- delimiter: ""
- human:
- format:
- delimiter: ""
- precision: 1
- storage_units:
- # Storage units output formatting.
- # %u is the storage unit, %n is the number (default: 2 MB)
- format: "%n %u"
- units:
- byte:
- one: "Byte"
- other: "Bytes"
- kb: "KB"
- mb: "MB"
- gb: "GB"
- tb: "TB"
-
- support:
- array:
- words_connector: ", "
- two_words_connector: " und "
- last_word_connector: " und "
- select:
- prompt: "Bitte wählen:"
-
- activemodel:
- errors:
- template:
- header:
- one: "Konnte %{model} nicht speichern: ein Fehler."
- other: "Konnte %{model} nicht speichern: %{count} Fehler."
- body: "Bitte überprüfen Sie die folgenden Felder:"
-
- activerecord:
- errors:
- template:
- header:
- one: "Konnte %{model} nicht speichern: ein Fehler."
- other: "Konnte %{model} nicht speichern: %{count} Fehler."
- body: "Bitte überprüfen Sie die folgenden Felder:"
-
- messages:
- inclusion: "ist kein gültiger Wert"
- exclusion: "ist nicht verfügbar"
- invalid: "ist nicht gültig"
- confirmation: "stimmt nicht mit der Bestätigung überein"
- accepted: "muss akzeptiert werden"
- empty: "muss ausgefüllt werden"
- blank: "muss ausgefüllt werden"
- 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)"
- taken: "ist bereits vergeben"
- not_a_number: "ist keine Zahl"
- greater_than: "muss größer als %{count} sein"
- greater_than_or_equal_to: "muss größer oder gleich %{count} sein"
- equal_to: "muss genau %{count} sein"
- less_than: "muss kleiner als %{count} sein"
- less_than_or_equal_to: "muss kleiner oder gleich %{count} sein"
- odd: "muss ungerade sein"
- even: "muss gerade sein"
- record_invalid: "Gültigkeitsprüfung ist fehlgeschlagen: %{errors}"
- models:
- article: Artikel
- supplier: Lieferant
- user: Benutzerinnen
- workgroup: Arbeitsgruppe
- ordergroup: Bestellgruppe
- attributes:
- article:
- price: Nettopreis
- gross_price: Bruttopreis
- unit: Einheit
- unit_quantity: Gebindegröße
- tax: MwSt
- deposit: Pfand
- stock_article:
- price: Nettopreis
- user:
- password: Passwort
- first_name: Vorname
\ No newline at end of file
diff --git a/config/locales/de/de.admin.yml b/config/locales/de/de.admin.yml
new file mode 100644
index 00000000..dec26c11
--- /dev/null
+++ b/config/locales/de/de.admin.yml
@@ -0,0 +1,103 @@
+de:
+ admin:
+ confirm: 'Willst du %{name} wirklich löschen?'
+ actions: 'Aktionen'
+ access_to: 'Zugriff auf'
+ search_placeholder: 'Name ...'
+ base:
+ index:
+ title: 'Administration'
+ first_paragraph: 'Hier kannst Du die Gruppen und Benutzerinnen der Foodsoft verwalten.'
+ newest_users: 'Neuste Benutzerinnen'
+ username: 'Benutzername'
+ name: 'Name'
+ created_at: 'Erstellt am'
+ all_users: 'Alle Benutzerinnen'
+ new_user: 'Neue Benutzerin'
+ newest_groups: 'Neuste Gruppen'
+ groupname: 'Gruppenname'
+ type: 'Typ'
+ members: 'Mitglieder'
+ all_ordergroups: 'Alle Bestellgruppen'
+ new_ordergroup: 'Neue Bestellgruppe'
+ all_workgroups: 'Alle Arbeitsgruppen'
+ new_workgroup: 'Neue Arbeitsgruppe'
+ ordergroups:
+ index:
+ title: 'Bestellgruppen'
+ new_ordergroup: 'Neue Bestellgruppe anlegen'
+ first_paragraph: 'Hier kannst du %{url} anlegen, Gruppen bearbeiten und löschen.'
+ new_ordergroups: 'neue Bestellgruppen'
+ second_paragraph: "Beachte dabei den Unterschied zwischen Gruppe und Bestellgruppe : Eine Bestellgruppe hat ein Konto und kann Essen bestellen. In einer %{url} (z.b. 'Soritiergruppe') koordinieren sich die Mitglieder mittels Aufgaben und Nachrichten. Nutzer_innen können immer nur einer Bestellgruppe, aber beliebig vielen anderen Gruppen angehören."
+ workgroup: 'Arbeitsgruppe'
+ edit:
+ title: 'Bestellgruppe bearbeiten'
+ new:
+ title: 'Bestellgruppe anlegen'
+ form:
+ first_paragraph: 'Neue Mitglieder kannst du %{url} einladen.'
+ here: 'hier'
+ show:
+ title: 'Bestellgruppe %{name}'
+ edit: 'Gruppe/Mitglieder bearbeiten'
+ confirm: 'Bist Du sicher?'
+ send_message: 'Nachricht senden'
+ ordergroups:
+ name: 'Name'
+ contact: 'Kontakt'
+ address: 'Adresse'
+ members: 'Mitglieder'
+ destroy:
+ notice: 'Bestellgruppe wurde gelöscht'
+ error: 'Bestellgruppe konnte nicht gelöscht werden: #{error}'
+ users:
+ index:
+ title: 'Admin/Benutzerinnen'
+ new_user: 'Neue Benutzerin anlegen'
+ first_paragraph: 'Hier kannst du Benutzer_innen %{url}, bearbeiten und natürlich auch löschen.'
+ new_users: 'neu anlegen'
+ edit:
+ title: 'Benutzerin bearbeiten'
+ new:
+ title: 'Neue Benutzerin anlegen'
+ show:
+ person: 'Person'
+ member_since: 'Mitglied seit %{time}'
+ nick: 'Nick'
+ name: 'Name'
+ email: 'Email'
+ phone: 'Telefon'
+ preference: 'Einstellungen'
+ groupabos: 'Gruppenabos'
+ confirm: 'Willst du %{user} wirklich rausschmeißen?'
+ send_message: 'Nachricht senden'
+ users:
+ login: 'Login'
+ name: 'Name'
+ email: 'Email'
+ last_login: 'Letzter login'
+ workgroups:
+ index:
+ title: 'Arbeitsgruppen'
+ new_workgroup: 'Neue Arbeitsgruppe anlegen'
+ first_paragraph: 'Hier kannst du %{url} anlegen, Gruppen bearbeiten und löschen.'
+ new_workgroups: 'neue Arbeitsgruppen'
+ second_paragraph: "Beachte dabei den Unterschied zwischen Gruppe und Bestellgruppe : Eine %{url} hat ein Konto und kann Essen bestellen. In einer Arbeitsgruppe (z.b. 'Soritiergruppe') koordinieren sich die Mitglieder mittels Aufgaben und Nachrichten. Nutzer_innen können immer nur einer Bestellgruppe, aber beliebig vielen anderen Gruppen angehören."
+ ordergroup: 'Bestellgruppe'
+ edit:
+ title: 'Arbeitsgruppe bearbeiten'
+ new:
+ title: 'Arbeitsgruppe anlegen'
+ form:
+ first_paragraph: 'Neue Mitglieder kannst du %{url} einladen.'
+ here: 'hier'
+ show:
+ title: 'Arbeitsgruppe %{name}'
+ edit: 'Gruppe/Mitglieder bearbeiten'
+ confirm: 'Bist Du sicher?'
+ workgroups:
+ name: 'Name'
+ members: 'Mitglieder'
+ destroy:
+ notice: 'Arbeitsgruppe wurde gelöscht'
+ error: 'Arbeitsgruppe konnte nicht gelöscht werden: #{error}'
diff --git a/config/locales/de/de.article_categories.yml b/config/locales/de/de.article_categories.yml
new file mode 100644
index 00000000..ca5b86d2
--- /dev/null
+++ b/config/locales/de/de.article_categories.yml
@@ -0,0 +1,18 @@
+de:
+ article_categories:
+ edit:
+ title: 'Kategorie ändern'
+ index:
+ title: 'Artikelkategorien'
+ new: 'Neue Kategorie anlegen'
+ confirm_delete: 'Bist Du sicher?'
+ new:
+ title: 'Neue Kategorie anlegen'
+
+ # used by controller
+ create:
+ notice: 'Die Kategorie wurde gespeichert'
+ update:
+ notice: 'Die Kategorie wurde aktualisiert'
+ destroy:
+ error: 'Kategorie konnte nicht gelöscht werden: %{message}'
diff --git a/config/locales/de/de.articles.yml b/config/locales/de/de.articles.yml
new file mode 100644
index 00000000..9a3837da
--- /dev/null
+++ b/config/locales/de/de.articles.yml
@@ -0,0 +1,120 @@
+de:
+ articles:
+ article:
+ last_update: 'zuletzt geändert: %{last_update} | Brutto: %{gross_price}'
+ confirm_delete: 'Bist du sicher?'
+ articles:
+ unit_quantity_short: 'GebGr'
+ unit_quantity_desc: 'Gebindegröße'
+ price_netto: 'Preis'
+ option_select: 'Aktion wählen ...'
+ option_delete: 'Artikel löschen'
+ confirm_delete: 'Willst Du wirklich alle gewählten Artikel löschen?'
+ option_not_available: 'Artikel sind nicht mehr verfügbar'
+ option_available: 'Artikel sind verfügbar'
+ destroy_active_article:
+ note: >
+ %{article} wird in laufenden Bestellungen verwendet und kann nicht gelöscht werden.
+ Bitte zuerst den Artikel aus den Bestellungen %{drop_link}.
+ drop: 'entfernen'
+ edit_all:
+ title: 'Alle Artikel von %{supplier} bearbeiten'
+ note: 'Pflichtfelder sind: Name, Einheit, (netto) Preis und Bestellnummer.'
+ warning: 'Achtung, alle Artikel werden aktualisiert!'
+ submit: 'Alle Artikel aktualisieren'
+ edit_all_table:
+ available_short: 'verf.'
+ available_desc: 'verfügbar'
+ price_short: 'Preis'
+ price_desc: 'Netto!'
+ unit_quantity_short: 'GebGr'
+ unit_quantity_desc: 'Gebindegröße'
+ order_number_short: 'Best.Nr.'
+ order_number_desc: 'Bestellnummer'
+ form:
+ title: 'Neuen Artikel einfügen'
+ index:
+ title: 'Artikel von %{supplier} (%{count})'
+ search_placeholder: Name ...
+ new: 'Neuer Artikel'
+ edit_all: 'Alle bearbeiten'
+ upload: 'Artikel hochladen'
+ new_order: 'Bestellung anlegen'
+ ext_db:
+ title: 'Externe Datenbank'
+ import: 'Suchen/Importieren'
+ sync: 'Synchronisieren'
+ change_supplier: 'Lieferant wechseln ...'
+ import:
+ title: 'Artikel importieren'
+ placeholder: Name ...
+ restrict_region: 'Nur aus der Region'
+ import_search_results:
+ not_found: 'Keine Artikel gefunden'
+ already_imported: 'schon importiert'
+ action_import: 'importieren'
+ sync:
+ title: 'Artikel mit externer Datenbank synchronisieren'
+ outlist:
+ title: 'Auslisten ...'
+ body: 'Folgende Artikel wurden ausgelistet und werden gelöscht :'
+ body_skip: 'Es müssen keine Artikel gelöscht werden.'
+ update:
+ title: 'Aktualisieren ...'
+ update_msg: 'Artikel müssen aktualisiert werden:'
+ 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.
+ unit_quantity_short: 'GebGr'
+ price_short: 'Price'
+ submit: 'Alle löschen/aktualisieren'
+ upload:
+ title: '%{supplier} / Artikel hochladen'
+ body: >
+ Die Datei muss eine Textdatei mit der Endung '.csv' sein. Die erste Zeile
+ wird beim Einlesen ignoriert.
+ Die Felder müssen mit einem Semikolon (';') getrennt und der Text mit doppelten
+ Anführungszeichen ("Text...") umklammert werden.
+ Als Zeichensatz wird UTF-8 erwartet. Korrekte Reihenfolge der Spalten:
+ fields:
+ status: 'Status (x=ausgelistet)'
+ season_amount: 'Staffelmenge'
+ season_price: 'Staffelpreis'
+ file_label: 'Bitte wähle eine kompatible Datei aus'
+ submit: 'Datei hochladen'
+ parse_upload:
+ title: '%{supplier} / Artikel hochladen'
+ body: >
+ Bitte überprufe die engelesenen Artikel.
+ Achtung, momentan gibt es keine Überprüfung auf doppelte Artikel.
+ submit: 'Speichere neue Artikel für %{supplier}'
+
+ # used by controller
+ controller:
+ update_all:
+ notice: 'Alle Artikel und Preise wurden aktualisiert'
+ update_sel:
+ notice_destroy: 'Alle gewählten Artikel wurden gelöscht'
+ notice_unavail: 'Alle gewählten Artikel wurden auf "nicht verfügbar" gesetzt'
+ notice_avail: 'Alle gewählten Artikel wurden auf "verfügbar" gesetzt'
+ notice_noaction: 'Keine Aktion ausgewählt!'
+ parse_upload:
+ notice: '%{count} Artikel sind erfolgreich analysiert.'
+ create_from_upload:
+ notice: 'Es wurden %{count} neue Artikel gespeichert.'
+ sync:
+ shared_alert: '%{supplier} ist nicht mit einer externen Datenbank verknüpft.'
+ notice: 'Der Katalog ist aktuell'
+ update_sync:
+ notice: 'Alle Artikel und Preise wurden aktualisiert'
+ error_invalid: 'Artikel sind fehlerhaft. Bitte überprüfe Deine Eingaben.'
+ error_nosel: 'Du hast keine Artikel ausgewählt'
+ error_invalid: 'Artikel sind fehlerhaft'
+ error_parse: '%{msg} ... in Zeile %{line}'
+ error_update: "Es trat ein Fehler beim Aktualisieren des Artikels '%{article}' auf: %{msg}"
+
+ # used by model
+ model:
+ error_in_use: '%{article} kann nicht gelöscht werden. Der Artikel befindet sich in einer laufenden Bestellung!'
+ error_nosel: 'Du hast keine Artikel ausgewählt'
diff --git a/config/locales/de/de.defaults.yml b/config/locales/de/de.defaults.yml
new file mode 100644
index 00000000..890ee796
--- /dev/null
+++ b/config/locales/de/de.defaults.yml
@@ -0,0 +1,321 @@
+de:
+ orders:
+ state:
+ open: laufend
+ finished: beendet
+ closed: abgerechnet
+
+ group_orders:
+ messages:
+ not_enough_apples: >
+ Um zu Bestellen brauchst Du mindestends %{stop_ordering_under} Äpfel.
+ Momentan hat Deine Bestellgruppe aber nur %{apples} Äpfel.
+ views:
+ pagination:
+ first: "«"
+ last: "»"
+ previous: "‹"
+ next: "›"
+ truncate: "..."
+
+ 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
+ errors: &errors
+ general: 'Ein Problem ist aufgetreten.'
+ general_msg: 'Ein Fehler ist aufgetreten: %{msg}'
+ general_again: 'Ein Fehler ist aufgetreten. Bitte erneut versuchen.'
+ format: ! '%{attribute} %{message}'
+ 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.'
+ 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: ''
+ support:
+ array:
+ last_word_connector: ! ' und '
+ two_words_connector: ! ' und '
+ words_connector: ! ', '
+ 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
+ # remove these aliases after 'activemodel' and 'activerecord' namespaces are removed from Rails repository
+ activemodel:
+ errors:
+ <<: *errors
+ activerecord:
+ errors:
+ <<: *errors
+ has_many_left: 'ist noch mit einem/r %{collection} verknüpft!'
+ models:
+ article: Artikel
+ supplier: Lieferant
+ user: Benutzerinnen
+ workgroup: Arbeitsgruppe
+ ordergroup: Bestellgruppe
+ task: Aufgabe
+ message: Nachricht
+ article_category: Artikelkategorie
+ stock_article: Lagerartikel
+ delivery: Lieferung
+ stock_taking: Inventur
+ financial_transaction: Kontotransaktion
+ order: Bestellung
+ order_comment: Kommentar
+ order_article: Bestell-Artikel
+ invoice: Rechnung
+ attributes:
+ article:
+ availability: 'Artikel ist verfügbar?'
+ price: Nettopreis
+ gross_price: Bruttopreis
+ unit: Einheit
+ unit_quantity: Gebindegröße
+ tax: MwSt
+ deposit: Pfand
+ article_category: Kategorie
+ stock_article:
+ price: Nettopreis
+ user:
+ password: Passwort
+ first_name: Vorname
+ financial_transaction:
+ amount: Betrag
+ note: Notiz
+
+ # messages in model that don't have a corresponding view
+ model:
+ membership:
+ no_admin_delete: 'Mitgliedschaft kann nicht beendet werden. Du bist die letzte Administratorin'
+ order_article:
+ error_price: 'muss angegeben sein und einen aktuellen Preis haben'
+ page:
+ redirect: 'Weiterleiting auf [[%{title}]]...'
+ user:
+ notify:
+ order_finished: 'Informier mich über meine Bestellergebnisse (nach Ende der Bestellung).'
+ negative_balance: 'Informiere mich, falls meine Bestellgruppe ins Minus rutscht.'
+ upcoming_tasks: 'Erinnere mich an anstehende Aufgaben.'
+ send_as_email: 'Bekomme Nachrichten als Emails.'
+ phone_is_public: 'Telefon ist für Mitglieder sichtbar'
+ email_is_public: 'E-Mail ist für Mitglieder sichtbar'
+ name_is_public: 'Name ist für Mitglieder sichtbar'
+ no_ordergroup: 'keine Bestellgruppe'
+
+ helpers:
+ select:
+ prompt: Bitte wählen
+ submit:
+ create: "%{model} speichern"
+ update: "Änderungen speichern"
+ message:
+ create: 'Nachricht verschicken'
+ invite:
+ create: Einladung verschicken
+ application:
+ sort_by: 'Nach %{text} sortieren'
+ edit_user: 'Mitglieder bearbeiten'
+ show_google_maps: 'Show it on Google maps'
+ # long names in simple_form.labels.workgroup
+ role_admin: 'Admin'
+ role_finance: 'Finanzen'
+ role_suppliers: 'Lieferanten'
+ role_article_meta: 'Artikel'
+ role_orders: 'Bestellung'
+ write_message: 'Nachricht_schreiben'
+ deliveries:
+ show_invoice: 'Rechnung anzeigen'
+ new_invoice: 'Rechnung anlegen'
+ orders:
+ order_pdf: 'PDF erstellen'
+ option_choose: 'Lieferantin/Lager auswählen'
+ option_stock: 'Lager'
+ tasks:
+ required_users: 'Es fehlen %{count} Mitstreiterinnen!'
+
+ lib:
+ order_pdf:
+ page: 'Seite %{number}'
+
+ # general user-interface
+ ui:
+ close: 'Schließen'
+ edit: 'Bearbeiten'
+ delete: 'Löschen'
+ show: 'Anzeigen'
+ save: 'Speichern'
+ or_cancel: 'oder abbrechen'
+ marks:
+ close: '×'
+
diff --git a/config/locales/de/de.deliveries.yml b/config/locales/de/de.deliveries.yml
new file mode 100644
index 00000000..fca2e48f
--- /dev/null
+++ b/config/locales/de/de.deliveries.yml
@@ -0,0 +1,42 @@
+de:
+ deliveries:
+ suppliers_overview: 'Lieferantenübersicht'
+ invoice_amount: 'Rechnungsbetrag'
+ invoice_net_amount: 'bereinigter Rechnungsbetrag'
+ edit:
+ title: 'Lieferung bearbeiten'
+ form:
+ remove_article: 'Artikel aus Lieferung entfernen'
+ add_article: 'Lagerartikel der Lieferung hinzufügen'
+ note_new_article: 'Ist ein Artikel noch nicht in der Lagerverwaltung, muss er erst %{new_link} werden.'
+ note_new_article_link: 'neu angelegt'
+ new_article:
+ title: 'Neuen Lagerartikel anlegen'
+ search: 'Suche nach Artikeln aus dem %{supplier} Katalog'
+ index:
+ title: '%{supplier}/Lieferungen'
+ confirm_delete: 'Bist Du sicher?'
+ new_delivery: 'Neue Lieferung für %{supplier} anlegen'
+ new:
+ title: 'Neue Lieferung von %{supplier}'
+ show:
+ title: 'Lieferung anzeigen'
+ title_articles: 'Artikel'
+ article: 'Artikel'
+ unit: 'Einheit'
+ amount: 'Menge'
+ price: 'Nettopreis'
+ sum: 'Summe'
+ sum_net: 'Nettosumme'
+ sum_gross: 'Bruttosumme'
+ sum_diff: 'Brutto - bereinigter Rechnungsbetrag'
+ stock_change:
+ remove_article: 'Artikel aus Lieferung entfernen'
+
+ # used by controller
+ create:
+ notice: 'Lieferung wurde erstellt. Bitte nicht vergessen die Rechnung anzulegen!'
+ update:
+ notice: 'Lieferung wurde aktualisiert.'
+ destroy:
+ notice: 'Lieferung wurde gelöscht.'
diff --git a/config/locales/de/de.documents.yml b/config/locales/de/de.documents.yml
new file mode 100644
index 00000000..cff7bb51
--- /dev/null
+++ b/config/locales/de/de.documents.yml
@@ -0,0 +1,41 @@
+de:
+ # for app/documents
+ documents:
+ order_by_articles:
+ filename: 'Bestellung %{name}-%{date} - Artikelsortierung'
+ title: 'Artikelsortierung der Bestellung: %{name}, beendet am %{date}'
+ rows:
+ - Bestellgruppe
+ - Menge
+ - Preis
+ order_by_groups:
+ filename: 'Bestellung %{name}-%{date} - Gruppensortierung'
+ title: 'Gruppensortierung der Bestellung: %{name}, beendet am %{date}'
+ rows:
+ - Artikel
+ - Menge
+ - Preis
+ - GebGr
+ - Einheit
+ - Summe
+ sum: 'Summe'
+ order_fax:
+ filename: 'Bestellung %{name}-%{date} - Fax'
+ rows:
+ - BestellNr.
+ - Menge
+ - Name
+ - Gebinde
+ - Einheit
+ - Preis/Einheit
+ order_matrix:
+ filename: 'Bestellung %{name}-%{date} - Sortiermatrix'
+ title: 'Sortiermatrix der Bestellung: %{name}, beendet am %{date}'
+ heading: 'Artikelübersicht'
+ total: 'Insgesamt %{count} Artikel'
+ rows:
+ - Artikel
+ - Einheit
+ - Gebinde
+ - FC-Preis
+ - Menge
diff --git a/config/locales/de/de.feedback.yml b/config/locales/de/de.feedback.yml
new file mode 100644
index 00000000..9a291ddd
--- /dev/null
+++ b/config/locales/de/de.feedback.yml
@@ -0,0 +1,10 @@
+de:
+ feedback:
+ create:
+ notice: "Das Feedback wurde erfolgreich verschickt. Vielen Dank!"
+ new:
+ title: 'Gib Feedback'
+ first_paragraph: 'Fehler gefunden? Vorschlag? Idee? Kritik? Wir freuen uns über jegliches Feedback.'
+ second_paragraph: 'Bitte beachte, dass das Foodsoft Team nur die Software wartet. Bei Fragen zur Organisation in Deiner Foodcoop,
+ kontaktiere besser die entsprechenden Ansprechpartner.'
+ send: 'Absenden'
\ No newline at end of file
diff --git a/config/locales/de/de.finance.yml b/config/locales/de/de.finance.yml
new file mode 100644
index 00000000..383db603
--- /dev/null
+++ b/config/locales/de/de.finance.yml
@@ -0,0 +1,170 @@
+de:
+ finance:
+ index:
+ title: 'Finanzbereich'
+ unpaid_invoices: 'Unbezahlte Rechnungen'
+ show_all: 'alle anzeigen'
+ date: 'Datum'
+ amount: 'Betrag'
+ supplier: 'Lieferantin'
+ last_transactions: 'letzte Überweisungen'
+ group: 'Gruppe'
+ note: 'Notiz'
+ open_transactions: 'noch nicht abgerechnet'
+ end: 'Ende'
+ amount_fc: 'Betrag(FC)'
+ clear: 'Abrechnen'
+ everything_cleared: 'Super, alles schon abgerechnet...'
+ balancing:
+ close:
+ notice: 'Bestellung wurde erfolgreich abgerechnet, die Kontostände aktualisiert.'
+ alert: 'Ein Fehler ist beim Abrechnen aufgetreten: %{message}'
+ close_direct:
+ notice: 'Bestellung wurde geschlossen.'
+ alert: 'Bestellung kann nicht geschlossen werden: %{message}'
+ index:
+ title: 'beendete Bestellungen'
+ new:
+ alert: 'Achtung, Bestellung wurde schon abgerechnet'
+ title: '%{name} abrechnen'
+ summary: 'Zusammenfassung'
+ invoice: 'Rechnung'
+ notes_and_journal: 'Notizen/Protokoll'
+ comment_on_transaction: 'Hier kannst Du deine Abrechnung kommentieren'
+ edit_note: 'Notiz bearbeiten'
+ comments: 'Kommentare'
+ create_invoice: 'Rechnung anlegen'
+ confirm_order: 'Bestellung abschließen'
+ view_options: 'Ansichtsoptionen'
+ edit_order: 'Bestellung bearbeiten'
+ groups_overview: 'Gruppenübersicht'
+ articles_overview: 'Artikelübersicht'
+ confirm:
+ title: 'Bestellung abschließen'
+ first_paragraph: 'Wenn die Bestellung abgeschlossen wird, werden ebenfalls alle Gruppenkonten aktualisiert. Die Konten werden wie folgt belastet:'
+ clear: 'Abschließen'
+ or_cancle: 'oder zurück zur Abrechnung'
+ summary:
+ duration: 'von %{starts} bis %{ends}'
+ net_amount: 'Nettobetrag:'
+ gross_amount: 'Bruttobetrag:'
+ fc_amount: 'FC-Betrag:'
+ groups_amount: 'Gruppenbeträge:'
+ fc_profit: 'FC Gewinn'
+ without_extra_charge: 'ohne Aufschlag:'
+ with_extra_charge: 'mit Aufschlag:'
+ changed: 'Daten wurden verändert!'
+ reload: 'Zusammenfassung neu laden'
+ orders:
+ name: 'Name'
+ end: 'Ende'
+ state: 'Status'
+ last_edited_by: 'zuletzt bearbeitet von'
+ cleared: 'abgerechnet (%{amount})'
+ clear: 'abrechnen'
+ close: 'direkt schließen'
+ confirm: 'Wirklich die Bestellung schließen setzen?'
+ no_closed_orders: 'derzeit gibt es keine beendeten Bestellungen'
+ order_article:
+ confirm: 'Bist du sicher?'
+ invoice:
+ invoice_number: 'Rechnungsnummer:'
+ invoice_date: 'Rechnungsdatum:'
+ invoice_amount: 'Rechnungsbetrag:'
+ minus_refund_calculated: '- Pfand berechnet:'
+ plus_refund_credited: '+ Pfand gutgeschrieben:'
+ refund_adjusted_amount: 'pfandbereinigter Betrag:'
+ edit: 'Rechnung bearbeiten'
+ new: 'Neue Rechnung erstellen'
+ group_order_articles:
+ group: 'Gruppe'
+ units: 'Einheiten'
+ total: 'Gesamtpreis'
+ add_group: 'Gruppe hinzufügen'
+ total_fc: 'Summe (FC-Preis)'
+ edit_results_by_articles:
+ article: 'Artikel'
+ number: 'Nr.'
+ amount: 'Menge'
+ amount_per_unit: 'GebGr * Einheit'
+ net: 'Netto'
+ gross: 'Brutto'
+ tax: 'MwSt'
+ refund: 'Pfand'
+ add_article: 'Artikel hinzufügen'
+ financial_transactions:
+ create:
+ notice: "Die Transaktion wurde gespeichert."
+ create_collection:
+ notice: "Alle Transaktionen wurden gespeichert."
+ alert: "Ein Fehler ist aufgetreten: %{error}"
+ ordergroup:
+ remove: "Entfernen"
+ remove_group: "Gruppe enfernen"
+ transactions:
+ date: "Datum"
+ who: "Wer"
+ note: "Notiz"
+ amount: "Betrag"
+ index:
+ title: "Kontoauszug für %{name}"
+ new_transaction: 'Neue Transaktion anlegen'
+ balance: 'Kontostand: %{balance}'
+ last_updated_at: '(zuletzt aktualisiert vor %{when})'
+ search_placeholder: 'Suchen ...'
+ new_collection:
+ title: "Mehrere Konten aktualisieren"
+ sidebar: 'Hier kannst Du mehrere Konten gleichzeitig aktualsieren. Z.B. alle Überweisungen der Bestellgruppen aus einem Kontoauszug.'
+ new_ordergroup: 'Weitere Bestellgruppe hinzufügen'
+ ordergroup: 'Bestellgruppe'
+ note: 'Notiz'
+ amount: 'Betrag'
+ save: "Transaktionen speichern"
+ new:
+ title: "Neue Transaktion"
+ paragraph: 'Hier kannst du der Bestellgruppe %{name} Geld gutschreiben/abziehen.'
+ group_order_articles:
+ form:
+ amount_change_for: 'Mengenänderung für %{article}'
+ ordergroups:
+ ordergroups:
+ name: "Name"
+ account_balance: "Kontostand"
+ new_transaction: "Neue Transaktion"
+ account_statement: "Kontoauszug"
+ index:
+ title: "Konten verwalten"
+ new_transaction: "Neue Überweisungen eingeben"
+ search_placeholder: 'Suchen ...'
+ invoices:
+ edit:
+ title: "Rechnung bearbeiten"
+ form:
+ linked: "Diese Rechnung ist mit einer %{what_link} verknüpft."
+ delivery: "Lieferung"
+ order: "Bestellung"
+ index:
+ title: "Rechnungen"
+ action_new: "Neue Rechnung anlegen"
+ invoices:
+ delivery: "Lieferung"
+ confirm_delete: "Bist Du sicher?"
+ new:
+ title: "Neue Rechnung anlegen"
+ back: "Züruck"
+ show:
+ title: "Rechnung %{number}"
+ linked: "Diese Rechnung ist mit einer %{what_link} verknüpft."
+ delivery: "Lieferung"
+ back: "Züruck"
+ order_articles:
+ edit:
+ title: 'Artikel aktualisieren'
+ new:
+ title: 'Neuer gelieferter Artikel die Bestellung'
+
+ # used by controller
+ create:
+ notice: 'Rechnung wurde erstellt.'
+ update:
+ notice: 'Rechnung wurde aktualisiert.'
diff --git a/config/locales/de/de.foodcoop.yml b/config/locales/de/de.foodcoop.yml
new file mode 100644
index 00000000..c1b93151
--- /dev/null
+++ b/config/locales/de/de.foodcoop.yml
@@ -0,0 +1,34 @@
+de:
+ foodcoop:
+ ordergroups:
+ index:
+ title: 'Bestellgruppen'
+ name: Name ...
+ only_active: 'Nur aktive'
+ only_active_desc: '(mindestens einmal in den letzten 3 Monaten bestellt)'
+ ordergroups:
+ name: 'Name'
+ user: 'Mitglieder'
+ last_ordered: 'zuletzt bestellt'
+ users:
+ index:
+ title: 'Mitglieder'
+ body: >
+ Hier kannst Du den Mitgliedern Deiner Foodcoop eine Nachricht schreiben.
+ Damit Deine Kontaktdaten einzusehen sind, musst Du sie unter %{profile_link} freigeben.
+ profile_link: 'Einstellungen'
+ ph_name: Name ...
+ ph_ordergroup: Bestellgruppe ...
+ workgroups:
+ index:
+ title: 'Arbeitsgruppen'
+ body: >
+ Das bearbeiten von Gruppen ist nur für Mitglieder der Gruppe möglich.
+ Wenn du einer Gruppe beitreten willst, dann schreib doch den Mitgliedern eine Nachricht.
+ edit:
+ title: 'Gruppe bearbeiten'
+ invite_new: 'Neue Mitglieder kannst du %{invite_link} einladen.'
+ invite_link: 'hier'
+ workgroup:
+ show_tasks: 'Alle Aufgaben zeigen'
+ edit: 'Gruppe bearbeiten'
diff --git a/config/locales/de/de.group_orders.yml b/config/locales/de/de.group_orders.yml
new file mode 100644
index 00000000..90cc0446
--- /dev/null
+++ b/config/locales/de/de.group_orders.yml
@@ -0,0 +1,98 @@
+de:
+ group_orders:
+ archive:
+ title: 'Bestellungen der %{group}'
+ desc: 'Siehe hier alle %{link}.'
+ open_orders: 'laufenden Bestellungen'
+ title_open: 'beendet/nicht abgerechnet'
+ title_closed: 'abgerechnet'
+ form:
+ title: 'Bestellen'
+ note: 'Notiz'
+ created_by: 'Erstellt von'
+ ending: 'Ende'
+ min_quantity: 'Mindestbestellmenge'
+ sum_amount: 'Gesamtbestellmenge bisher:'
+ last_update: 'Zuletzt bestellt'
+ funds: 'Guthaben'
+ name: 'Name'
+ supplier: 'Lieferant'
+ price: 'Preis'
+ unit: 'Einheit'
+ unit_missing: 'Fehlende Einheiten'
+ amount: 'Menge'
+ tolerance: 'Toleranz'
+ available: 'Verfügbar'
+ sum: 'Summe'
+ units: 'Gebinde'
+ units_full: 'Volle Gebinde'
+ total_units: 'Gesamt-Einheiten'
+ total_tolerance: 'Gesamt-Toleranz'
+ manufacturer: 'Hersteller'
+ total_sum_amount: 'Gesamtbetrag'
+ available_funds: 'Verfügbares Guthaben'
+ new_funds: 'Neuer Kontostand'
+ action_save: 'Bestellung speichern'
+ index:
+ title: 'Bestellüberblick'
+ funds:
+ title: 'Guthaben'
+ account_balance: 'Kontostand'
+ open_orders: 'laufende Bestellungen'
+ finished_orders: 'nicht abgerechnete Bestellungen'
+ available_funds: 'verfügbares Guthaben'
+ finished_orders:
+ title: 'Nicht abgerechnete Bestellungen'
+ total_sum: 'Gesamtsumme'
+ closed_orders:
+ title: 'Abgerechnete Bestellungen'
+ more: 'mehr...'
+ order:
+ title: 'Artikel'
+ # other fields reference group_orders.form
+ orders: &orders
+ supplier: 'Lieferantin'
+ ending: 'Ende'
+ sum: 'Summe'
+ show:
+ <<: *orders
+ title: 'Dein Bestellergebnis für %{order}'
+ note: 'Notiz'
+ order_sum: 'Bestellsumme'
+ not_ordered: 'Du hast nicht bestellt.'
+ closed_by: 'Abgerechnet von %{user}'
+ comment: 'Kommentare lesen/schreiben'
+ articles:
+ title: 'Artikelübersicht'
+ show_hide: 'Zeige/Verstecke nicht bestellte Artikel'
+ edit_order: 'Bestellung anpassen'
+ name: 'Name'
+ units: 'Gebinde'
+ unit_price: 'Einzelpreis'
+ ordered: 'Bestellt'
+ ordered_title: 'Menge + Toleranz'
+ order_open: 'Zu Erhalten'
+ order_not_open: 'Erhalten'
+ order_nopen_title: 'Unter Berücksichtigung der derzeitigen Bestellungen aller Gruppen'
+ total_price: 'Gesamtpreis'
+ sum: 'Summe'
+ not_ordered_msg: 'Du hast noch nicht bestellt'
+ order_now: 'Das ist Deine Chance!'
+ order_closed_msg: 'Die Bestellung is leider schon zu Ende. Beim nächsten mal früher aufstehen...'
+ comments:
+ title: 'Kommentare'
+ switch_order:
+ title: 'Laufende Bestellungen'
+ remaining: 'noch %{remaining}'
+
+ # used by controller
+ create: &create
+ notice: 'Die Bestellung wurde gespeichert.'
+ error_stale: 'In der Zwischenzeit hat jemand anderes auch bestellt, daher konnte die Bestellung nicht aktualisiert werden.'
+ error_general: 'Die Bestellung konnte nicht aktualisiert werden, da ein Fehler auftrat.'
+ update:
+ <<: *create
+ errors:
+ no_member: 'Du bist kein Mitglieder einer Bestellgruppe.'
+ closed: 'Diese Bestellung ist bereits abgeschlossen.'
+ notfound: 'Fehlerhafte URL, das ist nicht Deine Bestellung.'
diff --git a/config/locales/de/de.home.yml b/config/locales/de/de.home.yml
new file mode 100644
index 00000000..3ca3d6a1
--- /dev/null
+++ b/config/locales/de/de.home.yml
@@ -0,0 +1,85 @@
+de:
+ home:
+ index:
+ title: 'Startseite'
+ your_tasks: 'Deine Aufgaben'
+ due_date_format: '%A, %d. %b'
+ tasks_move:
+ title: 'Aufgaben übernehmen'
+ desc: 'Du bis für Aufgaben verantwortlich.'
+ action: 'Aufgaben übernehmen/ablehnen'
+ tasks_open:
+ title: 'Offene Aufgaben'
+ desc: 'Es gibt %{size}'
+ action: 'offene Aufgabe(n)'
+ ordergroup:
+ title: 'Engagement Deiner Bestellgruppe'
+ messages:
+ title: 'Neuste Nachrichten'
+ view_all: 'Alle Nachrichten einsehen'
+ my_ordergroup:
+ title: 'Meine Bestellgruppe'
+ funds: '| Verfügbares Guthaben:'
+ last_update: 'Letzte Aktualisiering ist %{when} her'
+ transactions:
+ title: 'Letzte Transaktionen'
+ when: 'Wann'
+ where: 'Wer'
+ note: 'Notiz'
+ amount: 'Betrag'
+ view: 'Kontoauszug anzeigen'
+
+ start_nav:
+ title: 'Direkt zu ...'
+ foodcoop: 'Foodcoop'
+ members: 'Mitglieder'
+ tasks: 'Meine Aufgaben'
+ write_message: 'Nachricht schreiben'
+ orders:
+ title: 'Bestellungen'
+ overview: 'Bestellübersicht'
+ end: 'Bestellungen beenden'
+ products:
+ title: 'Artikelverwaltung'
+ edit: 'Artikel aktualisieren'
+ edit_stock: 'Lagerverwaltung'
+ edit_suppliers: 'Lieferanten verwalten'
+ finances:
+ title: 'Finanzbereich'
+ accounts: 'Konten aktualisieren'
+ settle: 'Bestellungen abrechnen'
+ admin: 'Administration'
+ new_ordergroup: 'Neue Bestellgruppe'
+ new_user: 'Neues Mitglied'
+
+ apple_bar:
+ points: 'Deine aktueller Äpfelpunktestand: %{points}'
+ desc: 'Abgebildet ist das Verhältnis von erledigten Aufgaben zu dem Bestellvolumen Deiner Bestellgruppe im Vergleich zum Durchschnitt in der Foodcoop. Konkret: Pro %{amount} Bestellsumme solltest Du eine Aufgabe machen!'
+ warning: 'Achtung, hast Du weniger als %{threshold} Äpfel, darfst Du nicht mehr bestellen!'
+ more_info: 'Mehr Informationen'
+
+ ordergroup:
+ title: 'Meine Bestellgruppe'
+ description: 'Beschreibung'
+ funds: 'Verfügbares Guthaben:'
+ people: 'Personen'
+ invite: 'Neue Person einladen'
+ account_summary: 'Kontoauszug'
+ search: Suchen ...
+
+ profile:
+ title: 'Mein Profil'
+ user:
+ title: '%{user}'
+ since: '(Mitglied seit: %{when})'
+ groups:
+ title: 'Du bist Mitglied in folgenden Gruppen'
+ invite: 'Neue Mitglieder einladen'
+ cancel: 'Mitgliedschaft beenden'
+ cancel_confirm: 'Bist Du sicher, dass Du Deine Mitgliedschaft beenden willst?'
+
+ # used by controller
+ changes_saved: 'Änderungen wurden gespeichert.'
+ no_ordergroups: 'Leider bist Du kein Mitglied einer Bestellgruppe'
+ ordergroup_cancelled: 'Du bist jetzt kein Mitglied der Gruppe %{group} mehr.'
+
diff --git a/config/locales/de/de.invites.yml b/config/locales/de/de.invites.yml
new file mode 100644
index 00000000..28b3b6cd
--- /dev/null
+++ b/config/locales/de/de.invites.yml
@@ -0,0 +1,18 @@
+de:
+ invites:
+ new:
+ body: Hier kannst du eine Person in die Gruppe %{group} einladen, die noch nicht Mitglied der Foodcoop ist.
+ action: 'Einlading abschicken'
+ back: 'oder zurück'
+ modal_form:
+ title: 'Person einladen'
+ body: >
+ Hier kannst du eine Person in die Gruppe %{group} einladen, die noch nicht Mitglied der Foodcoop ist.
+ Die Person ist dann nach erstmaliger Anmeldung automatisch Mitglied dieser Gruppe.
+
+ # used by controller
+ success: 'Benutzerin wurde erfolgreich eingeladen.'
+
+ # used by model
+ errors:
+ already_member: 'ist bereits in Verwendung. Person ist schon Mitglied der Foodcoop.'
diff --git a/config/locales/de/de.layouts.yml b/config/locales/de/de.layouts.yml
new file mode 100644
index 00000000..838eebbb
--- /dev/null
+++ b/config/locales/de/de.layouts.yml
@@ -0,0 +1,21 @@
+de:
+ layouts:
+ foodsoft: 'Foodsoft'
+ logo: 'food soft'
+ header:
+ profile: 'Profil bearbeiten'
+ ordergroup: 'Meine Bestellgruppe'
+ logout: 'Abmelden'
+ help: 'Hilfe'
+ feedback:
+ title: 'Feedback'
+ desc: 'Fehler gefunden? Vorschlag? Idee? Kritik?'
+ footer: 'Foodsoft, open source software to manage a non-profit food coop.'
+ email:
+ footer: |
+ --
+ Foodsoft: %{foodsoft}
+ Foodcoop-Homepage: %{foodcoop}
+ Hilfe: %{help}
+ application1:
+ title: 'Foodsoft - %{title}'
diff --git a/config/locales/de/de.login.yml b/config/locales/de/de.login.yml
new file mode 100644
index 00000000..d4c905e5
--- /dev/null
+++ b/config/locales/de/de.login.yml
@@ -0,0 +1,39 @@
+de:
+ login:
+ accept_invitation:
+ title: 'Einlading in die %{name}'
+ body: >
+ Du bist eingeladen worden als Mitglied der Gruppe %{group}
+ in der Foodcoop %{foodcoop} mitzumachen.
+ Wenn Du mitmachen möchtest, dann fülle bitte dieses Formular aus.
+ Deine Daten werden selbstverständlich nicht an Dritte, aus was auch immer für
+ Gründen, weitergeben. Du kannst auch entscheiden, wieviel deiner persönlichen
+ Daten für alle einsehbar sein sollen. 'Alle' bedeutet hier alle Foodcoop-Mitglieder.
+ Die Administratoren haben aber jederzeit Zugriff auf deine Daten.
+ submit: 'Foodsoft Account erstellen'
+ forgot_password:
+ title: 'Passwort vergessen?'
+ body: >
+ Kein Problem, Du kannst dir einfach ein neues Passwort zulegen.
+ Dazu musst hier die E-Mail-Adresse eingeben, mit der Du in der Foodsoft angemeldet bist.
+ Du erhälst dann eine E-Mail mit weiteren Instruktionen.
+ submit: 'Neues Passwort anfordern'
+ new_password:
+ title: 'Neues Passwort'
+ body: >
+ Bitte neues Passwort für %{user} eingeben.
+ submit: 'Neues passwort speichern'
+
+ # used by controller
+ controller:
+ reset_password:
+ notice: 'Wenn Deine E-Mail hier registiert ist bekommst Du jetzt eine Nachricht mit einem Passwort-Zurücksetzen-Link.'
+ update_password:
+ notice: 'Dein Passwort wurde aktualisiert. Du kannst Dich jetzt anmelden.'
+ accept_invitation:
+ notice: 'Herzlichen Glückwunsch, Dein Account wurde erstellt. Du kannst Dich nun einloggen.'
+ error_invite_invalid: 'Deine Einladung ist nicht (mehr) gültig.'
+ error_group_invalid: 'Die Gruppe, in die Du eingeladen wurdest, existiert leider nicht mehr.'
+ error_token_invalid: 'Ungültiger oder abgelaufener Token. Bitte versuch es erneut.'
+
+
diff --git a/config/locales/de/de.mailer.yml b/config/locales/de/de.mailer.yml
new file mode 100644
index 00000000..ea0ec215
--- /dev/null
+++ b/config/locales/de/de.mailer.yml
@@ -0,0 +1,83 @@
+de:
+ mailer:
+ dateformat: '%d. %b'
+ feedback:
+ subject: 'Feedback von %{email}'
+ header: '%{user} schrieb am %{date}:'
+ foodsoft_message:
+ footer: |
+ Antworten: %{reply_url}
+ Nachricht online einsehen: %{msg_url}
+ Nachrichten-Einstellungen: %{profile_url}
+ invite:
+ subject: 'Einlading in die Foodcoop'
+ text: |
+ Hallo!
+
+ %{user} <%{mail}> hat dich in die Gruppe "%{group}" eingeladen.
+ Um die Einladung anzunehmen und der Foodcoop beizutreten, gehe zu: %{link}
+ Dieser Link kann nur einmal aufgerufen werden und ist nur bis %{expires} gültig.
+
+ Grüße sendet die Foodsoft!
+ negative_balance:
+ subject: 'Gruppenkonto im Minus'
+ text: |
+ Liebe %{group},
+
+ euer Kontostand is durch eine Buching am %{when} ins Minus gerutscht: %{balance}
+
+ Es wurden %{amount} für "%{note}" abgebucht, die Buchung wurde von %{user} erstellt.
+
+ Bitte zahlt so bald wie möglich wieder Geld ein, un das Gruppenkonto auszugleichen.
+
+ Viele Grüße von %{foodcoop}
+ not_enough_users_assigned:
+ subject: '"%{task}" braucht noch Leute!'
+ text: |
+ Liebe(r) %{user},
+
+ De Job '%{task}' Deiner Arbeitsgruppe ist am %{when} fällig
+ und es fehlen noch Mitstriterinnen!
+
+ Sofern Du Dich noch nicht für diese Aufgabe eingetragen hast ist des jetzt die Chance:
+
+ %{workgroup_tasks_url}
+
+ Deine Aufgaben: %{user_tasks_url}
+ order_result:
+ subject: 'Bestellung beendet: %{name}'
+ text0: |
+ Liebe %{ordergroup},
+
+ die Bestelling für "%{order}" wurde am %{when} von %{user} beendet.
+
+ Für Euch wurden die folgenden Artikel bestellt:
+ text1: |
+ Gesamtpreis: %{sum}
+
+ Bestelling unline einsehen: %{order_url}
+
+ Viele Grüße von %{foodcoop}
+ reset_password:
+ subject: 'Neues Password für %{username}'
+ text: |
+ Hallo %{user},
+
+ du (oder jemand anderes) hat auf der FoodSoft-Website ein neues Passwort angefordert.
+ Um ein neues Passwort einzugeben, gehe zu: %{link}
+ Dieser Link kann nur einmal aufgerufen werden und läuft am %{expires} ab.
+ Wenn du das Passwort nicht ändern möchtest oder diese Email nicht ausgelöst hast, brauchst du nichts zu tun.
+ Dein bisheriges Passwort wurde nicht geändert.
+
+ Grüße sendet die Foodsoft! :)
+ upcoming_tasks:
+ subject: 'Aufgaben werden fällig!'
+ text0: |
+ Liebe(r) %{user},
+
+ Du bist für "%{task}" eingetragen. Die Aufgabe ist morgen (%{when}) fällig!
+ nextweek: 'Aufgaben für die nächtste Woche:'
+ text1: |
+ Meine Aufgaben: %{user_tasks_url}
+
+ Viele Grüße von %{foodcoop}
diff --git a/config/locales/de/de.messages.yml b/config/locales/de/de.messages.yml
new file mode 100644
index 00000000..113911d2
--- /dev/null
+++ b/config/locales/de/de.messages.yml
@@ -0,0 +1,35 @@
+de:
+ messages:
+ index:
+ title: 'Nachrichten'
+ new: 'Neue Nachricht'
+ messages:
+ reply: 'Antworten'
+ new:
+ title: 'Neue Nachricht'
+ search_user: 'Nach Nutzerin suchen'
+ no_user_found: 'Keine Nutzerin gefunden'
+ search: 'Suche ...'
+ list:
+ desc: 'Nachrichten an alle verschickst Du bitte über den Verteiler: %{list}'
+ subscribe_msg: 'Eventuell musst Du Dich dem Verteiler erst bekannt machen.'
+ subscribe: 'Erklärungen zum Verteiler findest Du im %{link}.'
+ wiki: 'Wiki (Abschnitt Mailing-Liste)'
+ mail: 'z.b. mit einer Mail an %{email}.'
+ show:
+ title: 'Nachricht anzeigen'
+ from: 'Von:'
+ subject: 'Betreff:'
+ sent_on: 'Gesendet:'
+ reply: 'Antworten'
+ all_messages: 'Nachricht im Überblick'
+
+ # used by controller
+ create:
+ notice: 'Nachricht ist gespeichert und wird versendet.'
+
+ # used by model
+ model:
+ reply_subject: 'Re: %{subject}'
+ reply_header: '%{user} schrieb am %{when}:'
+ reply_indent: '> %{line}'
diff --git a/config/locales/de/de.navigation.yml b/config/locales/de/de.navigation.yml
new file mode 100644
index 00000000..c1e2e9e2
--- /dev/null
+++ b/config/locales/de/de.navigation.yml
@@ -0,0 +1,36 @@
+de:
+ # for config/navigation.rb
+ navigation:
+ dashboard: 'Dashboard'
+ foodcoop: 'Foodcoop'
+ members: 'Mitglieder'
+ workgroups: 'Arbeitsgruppen'
+ ordergroups: 'Bestellgruppen'
+ messages: 'Nachrichten'
+ tasks: 'Aufgaben'
+ wiki:
+ title: 'Wiki'
+ home: 'Startseite'
+ all_pages: 'Alle Seiten'
+ orders:
+ title: 'Bestellungen'
+ ordering: 'Bestellen!'
+ archive: 'Meine Bestellungen'
+ manage: 'Bestellverwaltung'
+ articles:
+ title: 'Artikel'
+ suppliers: 'Lieferanten/Artikel'
+ stock: 'Lager'
+ categories: 'Kategorien'
+ finances:
+ title: 'Finanzen'
+ home: 'Übersicht'
+ accounts: 'Konten verwalten'
+ balancing: 'Bestellungen abrechnen'
+ invoices: 'Rechnungen'
+ admin:
+ title: 'Administration'
+ home: 'Übersicht'
+ users: 'Benutzerinnen'
+ ordergroups: 'Bestellgruppen'
+ workgroups: 'Arbeitsgruppen'
diff --git a/config/locales/de/de.ordergroups.yml b/config/locales/de/de.ordergroups.yml
new file mode 100644
index 00000000..3de061e8
--- /dev/null
+++ b/config/locales/de/de.ordergroups.yml
@@ -0,0 +1,11 @@
+de:
+ ordergroups:
+ index:
+ title: 'Bestellgruppen'
+ edit:
+ title: 'Bestellgruppe bearbeiten'
+
+ # used by model
+ model:
+ invalid_balance: 'ist keine gültige Zahl'
+ error_single_group: '%{user} ist schon in einer anderen Bestellgruppe'
diff --git a/config/locales/de/de.orders.yml b/config/locales/de/de.orders.yml
new file mode 100644
index 00000000..2e5e9d49
--- /dev/null
+++ b/config/locales/de/de.orders.yml
@@ -0,0 +1,94 @@
+de:
+ orders:
+ articles:
+ name: 'Name'
+ unit_quantity: 'Gebinde'
+ prices: 'Netto-/Bruttopreis'
+ units_ordered: 'Bestellte Einheiten'
+ units_full: 'Volle Gebinde'
+ prices_sum: 'Summe (Netto/Brutto-Preise):'
+ article_count: 'Bestellte Artikel:'
+ edit:
+ title: 'Bestellung bearbeiten'
+ new:
+ title: 'Neue Bestellung anlegen'
+ form:
+ title: 'Artikel'
+ name: 'Name'
+ note: 'Notiz'
+ stockit: 'Verfügbar'
+ origin: 'Herkunft'
+ supplier: 'Hersteller'
+ unit_quantity: 'Gebinde'
+ prices: 'Price (netto/FC)'
+ select_all: 'Alle auswählen'
+ index:
+ title: 'Bestellungen verwalten'
+ new_order: 'Neue Bestellung anlegen'
+ open_orders: 'Laufende Bestellungen'
+ supplier: 'Lieferantin'
+ ending: 'Ende'
+ note: 'Notiz'
+ action_end: 'Beenden'
+ confirm_end: 'Willst Du wirklich die Bestellung %{order} beenden? Es gibt kein zurück.'
+ confirm_delete: 'Willst Du wirklich die Bestellung löschen?'
+ no_open_orders: 'Derzeit gibt es keine laufende Bestellungen.'
+ ended_orders: 'Beendete Bestellungen'
+ orders:
+ supplier: 'Lieferantin'
+ start: 'Start'
+ ending: 'Ende'
+ status: 'Status'
+ show:
+ title: 'Bestellung: %{name}'
+ warn_not_closed: 'Achtung, Bestellung wurde noch nicht abgerechnet.'
+ supplier: 'Lieferantin:'
+ note: 'Notiz:'
+ created_by: 'Erstellt von:'
+ begin: 'Beginn:'
+ ending: 'Ende:'
+ group_orders: 'Gruppenbestellungen:'
+ amounts: 'Netto/Bruttosumme:'
+ articles_ordered: 'Bestellte Artikel:'
+ action_end: 'Beenden!'
+ confirm_end: "Willst Du wirklich die Bestellung %{order} beenden?\nEs gibt kein zurück."
+ confirm_delete: 'Willst Du wirklich die Bestellung löschen?'
+ articles: 'Artikelübersicht'
+ sort_group: 'Sortiert nach Gruppen'
+ sort_article: 'Sortiert nach Artikeln'
+ comments_link: 'Kommentare'
+ download:
+ title: 'Download'
+ group_pdf: 'Gruppen PDF'
+ article_pdf: 'Artikel PDF'
+ matrix_pdf: 'Matrix PDF'
+ fax_pdf: 'Fax PDF'
+ fax_txt: 'Fax Text'
+ download_file: 'Download file'
+ comments:
+ title: 'Kommentare'
+
+ # used by controller
+ create:
+ notice: 'Die Bestellung wurde erstellt.'
+ update:
+ notice: 'Die Bestellung wurde aktualisiert.'
+ finish:
+ notice: 'Die Bestellung wurde beendet.'
+ fax:
+ heading: 'Bestellung für %{name}'
+ customer_number: 'Kundennummer'
+ delivery_day: 'Liefertag'
+ to_address: 'Versandaddresse'
+ articles: 'Artikel'
+ number: 'Nummer'
+ amount: 'Menge'
+ name: 'Name'
+
+ # used by model
+ model:
+ notice_close: 'Bestellung: %{name}, bis %{ends}'
+ error_closed: 'Bestellung wurde schon abgerechnet'
+ error_starts_before_ends: 'muss nach dem Bestellstart liegen (oder leer bleiben)'
+ error_nosel: 'Es muss mindestens ein Artikel ausgewählt sein'
+
diff --git a/config/locales/de/de.pages.yml b/config/locales/de/de.pages.yml
new file mode 100644
index 00000000..38d53617
--- /dev/null
+++ b/config/locales/de/de.pages.yml
@@ -0,0 +1,73 @@
+de:
+ pages:
+ title: 'Titel'
+ last_updated: 'Zuletzt aktualisiert'
+ all:
+ title: 'Alle Wikiseiten'
+ new_page: 'Neue Seite anlegen'
+ recent_changes: 'Letzte Änderungen'
+ title_list: 'Seiten-Liste'
+ site_map: 'Site Map'
+ search:
+ placeholder: 'Seitentitle ...'
+ action: 'Suche'
+ body:
+ title_toc: 'Inhalt'
+ edit:
+ title: 'Seite bearbeiten'
+ form:
+ preview: 'Vorschau'
+ help:
+ title: 'Schnelle Formatierungshilfe'
+ section_character: 'Zeichenformatierung'
+ italic: 'kursiv'
+ bold: 'fett'
+ noformat: 'Keine Wiki- Formatierung'
+ text: 'text'
+ section_block: 'Block-Formatierung'
+ headings: 'Überschriften'
+ heading: 'Ebene %{level}'
+ unordered_list: 'Listen mit Punkten'
+ list_item_1: 'Erster Punkt'
+ list_item_2: 'Zweiter Punkt'
+ ordered_list: 'Listen mit Zahlen'
+ section_link: 'Link-Formatierung'
+ wiki_links: 'Wiki-Links'
+ wiki_link_ex: 'Foodsoft Wiki Seite'
+ external_links: 'Externe Links'
+ external_link_ex: 'Externe Seite'
+ section_table: 'Tabellenformatierung'
+ see_tables: 'Siehe %{tables_link}'
+ tables_link: 'Tabellen'
+ new:
+ title: 'Neue Wikiseite anlegen'
+ page_list_item:
+ date_format: '%a, %d. %B %Y %H:%M:%S'
+ show:
+ edit: 'Seite bearbeiten'
+ versions: 'Versionen (%{count})'
+ subpages: 'Unterseiten'
+ title_versions: 'Versionen'
+ date_format: '%d.%m.%y %H:%M'
+ delete: 'Seite löschen'
+ delete_confirm: 'Achtung, auch alle Unterseiten werden gelöscht. Bist Du sicher?'
+ last_updated: 'Zuletzt bearbeitet von %{user} am %{when}'
+ version:
+ title: '%{title} - Version %{version}'
+ title_version: 'Version'
+ date_format: '%a, %d.%m.%Y, %H:%M Uhr'
+ author: 'Autor: %{user}'
+ view_current: 'Aktuelle Version sehen'
+ revert: 'Auf diese Version zurücksetzen'
+
+ # used by controller
+ cshow:
+ error_noexist: 'Seite existiert nicht!'
+ redirect_notice: 'Weitergeleitet von %{page} ...'
+ create:
+ notice: 'Seite wurde angelegt'
+ update:
+ notice: 'Seite wurde aktualisiert'
+ destroy:
+ notice: "Die Seite '%{page}' und alle Unterseiten wurden erfolgreich gelöscht"
+ error_stale_object: 'Achtung, die Seite wurde gerade von jemand anderes bearbeitet. Bitte versuche es erneut.'
diff --git a/config/locales/de/de.sessions.yml b/config/locales/de/de.sessions.yml
new file mode 100644
index 00000000..cf621abe
--- /dev/null
+++ b/config/locales/de/de.sessions.yml
@@ -0,0 +1,14 @@
+de:
+ sessions:
+ new:
+ title: 'Foodsoft login'
+ nojs: 'Achtung, Cookies und Javascript müssen aktiviert sein! %{link} bitte abschalten.'
+ noscript: 'NoScript'
+ user: 'Benutzerin'
+ password: 'Passwort'
+ login: 'Anmelden'
+ forgot_password: 'Passwort vergessen?'
+ # used in controller
+ logged_in: 'Logged in!'
+ logged_out: 'Logged out!'
+ login_invalid: 'Invalid email or password'
diff --git a/config/locales/de/de.shared.yml b/config/locales/de/de.shared.yml
new file mode 100644
index 00000000..87b99176
--- /dev/null
+++ b/config/locales/de/de.shared.yml
@@ -0,0 +1,68 @@
+de:
+ shared:
+ articles_by_articles:
+ ordergroup: 'Bestellgruppe'
+ ordered: 'Bestellt (Menge + Toleranz)'
+ received: 'Bekommen'
+ price: 'Gesamtpreis'
+ articles_by_groups:
+ name: 'Name'
+ units: 'Menge'
+ units_desc: 'Zugeteilte Einheiten'
+ fc_price: 'FC-Preis'
+ fc_price_desc: 'Preis incl. MwSt, Pfand und Foodcoop-Aufschlag'
+ unit_quantity: 'GebGr'
+ unit_quantity_desc: 'Gebindegröße'
+ unit: 'Einheit'
+ price: 'Gesamtpreis'
+ group_form_fields:
+ title: 'Wöchentliche Jobs'
+ search_user: 'Nach Nutzerin suchen'
+ user_not_found: 'Keine Nutzerin gefunden'
+ search: 'Suche ...'
+ group:
+ description: 'Beschreibung'
+ contact: 'Kontakt'
+ address: 'Adresse'
+ access: 'Zugriff auf'
+ members: 'Mitglieder'
+ weekly_job: 'wöchentlicher Job'
+ no_weekly_job: 'kein wöchentlicher Job definiert'
+ apple_limit: 'Äpfel-Bestellbeschränkung'
+ deactivated: 'deaktiviert'
+ activated: 'aktiviert'
+ loginInfo:
+ profile: 'Profil'
+ edit_profile: 'Profil bearbeiten'
+ homepage_title: 'Foodcoop Homepage besuchen'
+ # duplicate from de.layouts.header
+ logout: 'Abmelden'
+ help: 'Hilfe'
+ feedback:
+ title: 'Feedback'
+ desc: 'Fehler gefunden? Vorschlag? Idee? Kritik?'
+ open_orders:
+ title: 'Laufende Bestellungen'
+ not_enough_apples: 'Achtung, Deine Bestellgruppe hat zu wenig Äpfel um Bestellen zu können!'
+ supplier: 'Lieferantin'
+ ending: 'Ende'
+ who_ordered: 'Wer hat bestellt?'
+ total: 'Summe'
+ total_sum: 'Gesamtsumme'
+ no_open_orders: 'Derzeit gibt es keine laufenden Bestellungen'
+ workgroup_members:
+ title: 'Mitglieder der Gruppen'
+
+ memberships:
+ current_members:
+ drop: 'entfernen'
+ no_members: '%{group} hat keine Mitglieder.'
+ members:
+ title: 'Mitglieder von %{group}'
+ desc: 'Hier kannst Du Mitglieder der Gruppe verwalten oder ein neues Foodcoop-Mitglied in die Gruppe %{link}.'
+ invite: 'einladen'
+ already_members: 'Sind schon Mitglieder'
+ no_members_yet: 'Sind noch keine Mitglieder'
+ invite_someone: 'Person einladen'
+ non_members:
+ add: 'hinzufügen'
diff --git a/config/locales/de/de.simple_form.yml b/config/locales/de/de.simple_form.yml
new file mode 100644
index 00000000..5aa5279a
--- /dev/null
+++ b/config/locales/de/de.simple_form.yml
@@ -0,0 +1,149 @@
+de:
+ # Simple form i18n is used to build the forms
+ simple_form:
+ "yes": 'Ja'
+ "no": 'Nein'
+ required:
+ text: 'benötigt'
+ mark: '*'
+ error_notification:
+ default_message: "Fehler wurden gefunden. Bitte das Formular überprüfen."
+ labels:
+ defaults:
+ password: 'Passwort'
+ password_confirmation: 'Passwort wiederholen'
+ description: 'Beschreibung'
+ title: 'Titel'
+ email: 'E-Mail'
+ note: 'Notiz'
+ date: 'Datum'
+ ordergroup: 'Bestellgruppe'
+ amount: 'Betrag'
+ phone: "Telefon"
+ user_tokens: 'Mitglieder'
+ price: 'Preis (netto)'
+ unit_quantity: 'Gebindegröße'
+ order_number: 'Bestellnummer'
+ tax: 'MwSt'
+ deposit: 'Pfand'
+ user:
+ nick: "Benutzerinnenname"
+ first_name: "Vorname"
+ last_name: "Nachname"
+ workgroup:
+ weekly_task: 'Monatlichen Job definieren?'
+ weekday: 'Wochentag'
+ task_name: 'Name für Job'
+ task_required_users: 'Benötige Verantwortliche'
+ task_duration: 'Vor. Dauer in Stunden'
+ task_description: 'Beschreibung'
+ next_weekly_tasks_number: "Für wieviel Wochen im Voraus sollen Aufgaben erstellt werden?"
+ role_admin: "Administration"
+ role_finance: "Finanzen"
+ role_suppliers: "Lieferanten"
+ role_article_meta: "Artikeldatenbank"
+ role_orders: "Bestellverwaltung"
+ ordergroup:
+ contact_person: "Kontaktperson"
+ contact_phone: "Telefon"
+ contact_address: "Adresse"
+ ignore_apple_restriction: "Bestellstop bei zu wenig Äpfeln ignorieren"
+ task:
+ name: 'Name'
+ duration: 'Dauer'
+ user_list: 'Verantwortliche'
+ required_users: 'Anzahl'
+ due_date: 'Wann erledigen?'
+ workgroup: 'Arbeitsgruppe'
+ done: Erledigt?
+ message:
+ sent_to_all: 'An alle Mitglieder schicken'
+ recipient_tokens: 'Empfänger_innen'
+ group_id: 'Gruppe'
+ subject: 'Betreff'
+ body: 'Inhalt'
+ private: Privat
+ page:
+ body: 'Inhalt'
+ parent_id: Oberseite
+ supplier:
+ name: 'Name'
+ address: 'Adresse'
+ phone: 'Telefon'
+ phone2: 'Telefon 2'
+ fax: 'FAX'
+ email: 'Email'
+ url: 'Homepage'
+ contact_person: 'Ansprechparter_in'
+ customer_number: 'Kundennummer'
+ delivery_days: 'Liefertage'
+ order_howto: 'Howto Bestellen'
+ note: 'Notiz'
+ min_order_quantity: 'Mindestbestellmenge'
+ is_subscribed: 'abonniert?'
+ article:
+ name: 'Name'
+ origin: 'Herkunft'
+ manufacturer: 'Produzent'
+ unit: 'Einheit'
+ note: 'Notiz'
+ article_category: 'Kategorie'
+ article_category:
+ name: 'Name'
+ description: 'Beschreibung'
+ stock_article:
+ supplier: 'Lieferant'
+ delivery:
+ supplier: 'Lieferantin'
+ delivered_on: 'Lieferdatum'
+ user:
+ nick: "Benutzername"
+ name: "Name"
+ last_name: "Nachname"
+ email: 'Email'
+ phone: "Telefon"
+ ordergroup: 'Bestellgruppe'
+ workgroup:
+ one: 'Arbeitsgruppe'
+ other: 'Arbeitsgruppen'
+ order_comment:
+ text: Kommentiere diese Bestellung ...
+ order:
+ starts: "Läuft vom"
+ ends: "Endet am"
+ order_article:
+ article_id: Artikel aus dem Katalog wählen
+ group_order_article:
+ ordergroup_id: Bestellgruppe
+ result: Menge
+ invoice:
+ supplier: Lieferant
+ number: Nummer
+ date: Rechnungsdatum
+ paid_on: Bezahlt am
+ deposit: Pfand berechnet
+ deposit_credit: Pfand gutgeschrieben
+ amount: Betrag
+ delivery: Lieferung
+ order: Bestellung
+ note: Notiz
+ order_article:
+ units_to_order: Menge
+ update_current_price: Globalen Preis aktualisieren
+
+ hints:
+ tax: 'In Prozent, Standard sind 7,0'
+ task:
+ duration: 'Wie lange dauert die Aufgabe, 1-3 Stunden'
+ required_users: 'Wieviel Benutzerinnen werden insgesamt benötigt?'
+ supplier:
+ min_order_quantity: 'Die Mindestbestellmenge wird während der Bestellung angezeigt und soll motivieren'
+ article:
+ unit: 'z.B. KG oder 1L oder 500g'
+ stock_article:
+ supplier: ''
+ message:
+ private: Nachricht erscheint nicht im Foodsoft Posteingang
+ order_article:
+ units_to_order: Anzahl gelieferter Gebinde
+ update_current_price: Ändert auch den Preis für aktuelle Bestellungen
diff --git a/config/locales/de/de.stock_takings.yml b/config/locales/de/de.stock_takings.yml
new file mode 100644
index 00000000..e3f873a7
--- /dev/null
+++ b/config/locales/de/de.stock_takings.yml
@@ -0,0 +1,34 @@
+de:
+ stock_takings:
+ edit:
+ title: 'Inventur bearbeiten'
+ index:
+ title: 'Inventurübersicht'
+ new_inventory: 'Neue Inventur anlegen'
+ new:
+ title: 'Neue Inventur anlegen'
+ text_deviations: 'Bitte trage hier alle gezählten Abweichungen vom %{inv_link} ein. Bei Schwund benutze einfach ein Minus vor der Zahl.'
+ temp_inventory: 'vorläufigen Lagerbestand'
+ text_need_articles: 'Einen neuen Lagerartikel musst Du vorher %{create_link} bevor Du Ihn hier verwenden kannst.'
+ create: 'anlegen'
+ stock_articles: 'Lagerartikel'
+ show:
+ title: 'Inventur anzeigen'
+ date: 'Datum'
+ note: 'Notiz'
+ article: 'Artikel'
+ supplier: 'Lieferantin'
+ unit: 'Einheit'
+ amount: 'Menge'
+ overview: 'Inventurübersicht'
+ confirm_delete: 'Willst Du wirklicht die Inventur löschen?'
+ stock_takings:
+ date: 'Datum'
+ note: 'Notiz'
+ confirm_delete: 'Bist Du sicher?'
+
+ # used by controller
+ create:
+ notice: 'Inventur wurde erfolgreich angelegt.'
+ update:
+ notice: 'Inventur wurde aktualisiert.'
diff --git a/config/locales/de/de.stockit.yml b/config/locales/de/de.stockit.yml
new file mode 100644
index 00000000..0a72bfa8
--- /dev/null
+++ b/config/locales/de/de.stockit.yml
@@ -0,0 +1,42 @@
+de:
+ stockit:
+ edit:
+ 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.'
+ index:
+ view_options: 'Ansichtsoptionen'
+ toggle_unavailable: 'Nicht verfügbare Artikel zeigen/verstecken'
+ order_online: 'Lagerbestellung online stellen'
+ new_stock_article: 'Neuen Lagerartikel anlegen'
+ new_stock_taking: 'Inventur anlegen'
+ show_stock_takings: 'Inventurübersicht'
+ new_delivery: 'Neue Lieferung ..'
+ article:
+ article: 'Artikel'
+ stock: 'im Lager'
+ ordered: 'davon bestellt'
+ available: 'verfügbar'
+ unit: 'Einheit'
+ price: 'Preis'
+ vat: 'MwSt'
+ supplier: 'Lieferantin'
+ category: 'Kategorie'
+ confirm_delete: 'Bist Du sicher?'
+ stock_worth: 'Aktueller Lagerwert:'
+ stock_count: 'Artikelanzahl:'
+ new:
+ title: 'Neuen Lagerartikel anlegen'
+ search_text: 'Suche nache Artikeln aus allen Katalogen:'
+ destroy:
+ notice: 'Artikel %{name} gelöscht.'
+
+ # used by controller
+ stock_create:
+ notice: 'Lagerartikel wurde gespeichert.'
+ stock_update:
+ notice: 'Lagerartikel wurde gespeichert.'
+
+ # used by model
+ check:
+ not_empty: '%{name} kann nicht gelöscht werden. Der Lagerbestand ist nicht null.'
diff --git a/config/locales/de/de.suppliers.yml b/config/locales/de/de.suppliers.yml
new file mode 100644
index 00000000..77d6b4e8
--- /dev/null
+++ b/config/locales/de/de.suppliers.yml
@@ -0,0 +1,36 @@
+de:
+ suppliers:
+ shared_supplier_note: 'Lieferantin ist mit externer Datenbank verknüpft.'
+ index:
+ title: 'Lieferanten'
+ action_new: 'Neue Lieferantin anlegen'
+ action_import: 'Lieferantin aus externer Datenbank importieren'
+ articles: 'Artikel (%{count})'
+ stock: 'im Lager (%{count})'
+ deliveries: 'Lieferungen (%{count})'
+ confirm_del: 'Achtung, willst Du wirklich den Lieferanten %{name} löschen?'
+ edit:
+ title: 'Lieferantin bearbeiten'
+ new:
+ title: 'Neue Lieferantin'
+ show:
+ confirm_delete: 'Bist Du sicher?'
+ last_deliveries: 'Letzte Lieferungen'
+ new_delivery: 'Neue Lieferung anlegen'
+ show_deliveries: 'Zeige alle Lieferungen'
+ shared_suppliers:
+ title: 'Externe Listen'
+ body: >
+ Hier werden die Lieferantinnen der externen Datenbank angezeigt.
+ Ihr könnt externe Lieferantinnen importieren, indem ihr sie einfach abonniert. (siehe unten)
+ Damit wird eine neue Lieferantin angelegt und mit der externen Datenbank verknüpft.
+ supplier: 'Lieferantin'
+ subscribe: 'abonnieren'
+
+ # used by controller
+ create:
+ notice: 'Lieferant wurde erstellt'
+ update:
+ notice: 'Lieferant wurde aktualisiert'
+ destroy:
+ notice: 'Lieferant wurde gelöscht'
diff --git a/config/locales/de/de.tasks.yml b/config/locales/de/de.tasks.yml
new file mode 100644
index 00000000..972eb9a1
--- /dev/null
+++ b/config/locales/de/de.tasks.yml
@@ -0,0 +1,75 @@
+de:
+ tasks:
+ archive:
+ title: 'Aufgabenarchiv'
+ archive_tasks:
+ due_date: 'Fälligkeitsdatum'
+ task: 'Betreff'
+ who: 'Verantwortliche Menschen'
+ task_format: '%{name} (%{duration}h)'
+ edit:
+ title: 'Aufgabe bearbeiten'
+ form:
+ search:
+ hint: "Nach Nutzerin suchen"
+ noresult: 'Keine Nutzerin gefunden'
+ placeholder: 'Suche ...'
+ index:
+ title: 'Aufgaben'
+ title_non_group: 'Aufgaben für alle!'
+ show_group_tasks: 'Gruppenaufgaben anzeigen'
+ list:
+ due_date: 'Fälligkeit'
+ task: 'Betreff'
+ who: 'Wer machts?'
+ who_hint: '(Wie viele werden noch benötigt?)'
+ task_format: '%{name} (%{duration}h)'
+ accept_task: 'Aufgabe übernehmen'
+ reject_task: 'Aufgabe ablehnen'
+ mark_done: 'Aufgabe als erledigt markieren'
+ done_q: 'Erledigt?'
+ done: 'Erledigt'
+ nav:
+ new_task: 'Neue Aufgabe erstellen'
+ my_tasks: 'Meine Aufgaben'
+ all_tasks: 'Alle Aufgaben'
+ archive: 'Erledigte Aufgaben (Archiv)'
+ group_tasks: 'Gruppenaufgaben'
+ new:
+ title: 'Neue Aufgabe erstellen'
+ show:
+ title: 'Aufgabe anzeigen'
+ hours: '%{count}h'
+ due_date: 'Fälligkeitsdatum'
+ accept_task: 'Aufgabe übernehmen'
+ reject_task: 'Aufgabe ablehnen'
+ mark_done: 'Als erledigt markieren'
+ user:
+ title: 'Meine Aufgaben'
+ title_open: 'Offene Aufgaben'
+ title_accepted: 'Anstehende Aufgaben'
+ more: 'Nichts zu tun? %{tasks_link} gibt es bestimmt Arbeit'
+ tasks_link: 'Hier'
+ workgroup:
+ title: 'Aufgaben für %{workgroup}'
+ weekly:
+ title: 'Wöchentliche Aufgaben'
+ desc: >
+ Jeden %{weekday} hat diese Arbeitsgruppe folgenden Job: %{task}
+ Die Wochenaufgaben werden von der Foodsoft automatisch erstellt. Eintragen müsst Ihr Euch aber selber.
+ empty: 'Noch keine Wochenaufgaben angelegt.'
+ edit: 'Wöchentliche Aufgaben anpassen'
+ title_all: 'Alle Aufgaben der Gruppe'
+
+ # used by controller
+ create:
+ notice: 'Aufgabe wurde erstellt'
+ update:
+ notice: 'Aufgabe wurde aktualisiert'
+ destroy:
+ notice: 'Aufgabe wurde gelöscht'
+ accept:
+ notice: 'Du hast die Aufgabe übernommen'
+ set_done:
+ notice: 'Aufgabenstatus wurde aktualisiert'
+ error_not_found: 'Keine Arbeitsgruppe gefunden'
diff --git a/config/locales/de/de.workgroups.yml b/config/locales/de/de.workgroups.yml
new file mode 100644
index 00000000..c6e8fc7e
--- /dev/null
+++ b/config/locales/de/de.workgroups.yml
@@ -0,0 +1,12 @@
+de:
+ workgroups:
+ edit:
+ title: 'Arbeitsgruppe bearbeiten'
+ index:
+ title: 'Arbeitsgruppen'
+
+ # used by controller
+ update:
+ notice: 'Arbeitsgruppe wurde aktualisiert'
+ error_last_admin_group: 'Die letzte Gruppe mit Admin-Rechten darf nicht gelöscht werden'
+ error_last_admin_role: 'Der letzten Gruppe mit Admin-Rechten darf die Admin-Rolle nicht entzogen werden'
diff --git a/config/locales/en.yml b/config/locales/en.yml
deleted file mode 100644
index f265c068..00000000
--- a/config/locales/en.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-# Sample localization file for English. Add more files in this directory for other locales.
-# See http://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
-
-en:
- hello: "Hello world"
\ No newline at end of file
diff --git a/config/locales/en/en.admin.yml b/config/locales/en/en.admin.yml
new file mode 100644
index 00000000..7f2a237e
--- /dev/null
+++ b/config/locales/en/en.admin.yml
@@ -0,0 +1,97 @@
+en:
+ admin:
+ confirm: 'Do you really want to delete %{name}?'
+ actions: 'Actions'
+ access_to: 'access to'
+ search_placeholder: 'name ..'
+ base:
+ index:
+ title: 'Administration'
+ first_paragraph: 'Here you can administer Foodsoft groups and users.'
+ newest_users: 'newest users'
+ username: 'username'
+ name: 'name'
+ created_at: 'created at'
+ all_users: 'All users'
+ new_user: 'New user'
+ newest_groups: 'newest groups'
+ groupname: 'group name'
+ type: 'type'
+ members: 'members'
+ all_ordergroups: 'All ordergroups'
+ new_ordergroup: 'New ordergroup'
+ all_workgroups: 'All workgroups'
+ new_workgroup: 'New workgroup'
+ ordergroups:
+ index:
+ title: 'Ordergroup'
+ new_ordergroup: 'Add new ordergroup'
+ first_paragraph: 'Here you can add a %{url}, administer a group or delete it.'
+ new_ordergroups: 'new ordergroups'
+ second_paragraph: "Consider the difference between group and ordergroup : An ordergroup has an account and can order food. In a %{url} (for example 'sorting group') the members coordinate with each other via tasks and messages. Users can only be in one ordergroup, but can be in multiple other groups."
+ workgroup: 'workgroup'
+ edit:
+ title: 'Edit ordergroup'
+ new:
+ title: 'Create ordergroup'
+ form:
+ first_paragraph: 'You can invite new members %{url}.'
+ here: 'here'
+ show:
+ title: 'Ordergroup %{name}'
+ edit: 'Edit group/member'
+ confirm: 'Are you sure?'
+ send_message: 'Send message'
+ ordergroups:
+ name: 'Name'
+ contact: 'Contact'
+ address: 'Address'
+ members: 'Members'
+ users:
+ index:
+ title: 'Admin/users'
+ new_user: 'Create new user'
+ first_paragraph: 'Here you can edit users %{url}, bearbeiten and also delete them.'
+ new_users: 'Create new user'
+ edit:
+ title: 'Edit user'
+ new:
+ title: 'Create new user'
+ show:
+ person: 'Person'
+ member_since: 'Member since %{time}'
+ nick: 'Nick'
+ name: 'Name'
+ email: 'Email'
+ phone: 'Phone'
+ preference: 'Preferences'
+ groupabos: 'Group subscriptions'
+ confirm: 'Do you really want to kick out %{user}?'
+ send_message: 'Send message'
+ users:
+ login: 'login'
+ name: 'name'
+ email: 'email'
+ last_login: 'last login'
+ workgroups:
+ index:
+ title: 'Workgroups'
+ new_workgroup: 'Create new workgroup'
+ first_paragraph: 'Here you can create %{url}, edit and delete them.'
+ new_workgroups: 'new workgroups'
+ second_paragraph: "Be aware of the difference between a group and ordergroup : A %{url} has an account and can order food. In a workgroup (for example 'sorting group') the members coordinate with each other via tasks and messages. Users can only be in one ordergroup, but can be in multiple other groups."
+ ordergroup: 'ordergroup'
+ edit:
+ title: 'Edit workgroup'
+ new:
+ title: 'Create workgroup'
+ form:
+ first_paragraph: 'You can invite new members %{url}.'
+ here: 'here'
+ show:
+ title: 'Workgroup %{name}'
+ edit: 'Edit group/members'
+ confirm: 'Are you sure?'
+ workgroups:
+ name: 'name'
+ members: 'members'
diff --git a/config/locales/en/en.article_categories.yml b/config/locales/en/en.article_categories.yml
new file mode 100644
index 00000000..3dca8144
--- /dev/null
+++ b/config/locales/en/en.article_categories.yml
@@ -0,0 +1,18 @@
+en:
+ article_categories:
+ edit:
+ title: 'Edit category'
+ index:
+ title: 'Article categories'
+ new: 'Add new category'
+ confirm_delete: 'Are you sure?'
+ new:
+ title: 'Add new category'
+
+ # used by controller
+ create:
+ notice: 'Category was stored'
+ update:
+ notice: 'Category was updated'
+ destroy:
+ error: 'Category could not be deleted: %{message}'
diff --git a/config/locales/en/en.articles.yml b/config/locales/en/en.articles.yml
new file mode 100644
index 00000000..b759aa05
--- /dev/null
+++ b/config/locales/en/en.articles.yml
@@ -0,0 +1,114 @@
+en:
+ articles:
+ article:
+ last_update: 'last updated: %{last_update} | Gross: %{gross_price}'
+ confirm_delete: 'Are you sure?'
+ articles:
+ unit_quantity_short: 'Quantity'
+ unit_quantity_desc: 'Unit quantity'
+ price_netto: 'Price'
+ option_select: 'Choose special offer ...'
+ option_delete: 'Delete article'
+ confirm_delete: 'Do you really want to delete all selected articles?'
+ option_not_available: 'Articles are not available anymore'
+ option_available: 'Articles are available'
+ destroy_active_article:
+ note: >
+ %{article} is used in current orders and can not be deleted
+ Please first ... the article from orders %{drop_link}.
+ drop: 'delete'
+ edit_all:
+ title: 'Edit all articles from %{supplier}'
+ note: 'Mandatory fields are: name, unit, (net) price and order number.'
+ warning: 'Warning: all articles will be updated!'
+ submit: 'Updating all articles'
+ edit_all_table:
+ available_short: 'avail'
+ available_desc: 'available'
+ price_short: 'Price'
+ price_desc: 'Net price'
+ unit_quantity_short: 'Quantity'
+ unit_quantity_desc: 'Unit quantity'
+ order_number_short: 'Ordernr.'
+ order_number_desc: 'Order number'
+ form:
+ title: 'Add new article'
+ index:
+ title: 'Article from %{supplier} (%{count})'
+ search_placeholder: Name ...
+ new: 'New article'
+ edit_all: 'Edit all'
+ upload: 'Upload articles'
+ new_order: 'Create new order'
+ ext_db:
+ title: 'External databank'
+ import: 'Search/Import'
+ sync: 'Synchronise'
+ change_supplier: 'Change supplier ...'
+ import:
+ title: 'Import article'
+ placeholder: Name ...
+ restrict_region: 'Restrict to region only'
+ import_search_results:
+ not_found: 'No articles found'
+ already_imported: 'already imported'
+ action_import: 'import'
+ sync:
+ title: 'Synchronise articles with external database'
+ outlist:
+ title: 'Put from the list ...'
+ body: 'The following articles are put from the list and will be deleted :'
+ body_skip: 'No articles for deletion.'
+ update:
+ title: 'Update ..'
+ update_msg: 'Articles must be updated:'
+ body: >
+ Every article is shown twice. The old value is gray and the textfields are pre-filled with the actual value now.
+ Differences with the old articles are marked yellow
+ unit_quantity_short: 'Unity Quan.'
+ price_short: 'Price'
+ submit: 'Delete/update all'
+ upload:
+ title: '%{supplier} / upload articles'
+ body: >
+ The file has to be a text file with the ending '.csv' The first line will be ignored when imported
+ The fields have to be separated with semicolons (';') and the text enclosed by double quotation marks ("text...").
+ As character set UTF-8 is demanded. Correct order of the column:
+ fields:
+ status: 'Status (x=skip)'
+ season_amount: 'Scaled amount'
+ season_price: 'Scaled price'
+ file_label: 'Please choose a compatible file'
+ submit: 'Upload file'
+ parse_upload:
+ title: '%{supplier} / upload article'
+ body: >
+ Please check the imported articles.
+ Note: at the moment there is no check for duplicate articles.
+ submit: 'Save new articles for %{supplier}'
+
+ # used by controller
+ update_all:
+ notice: 'All articles and prices are updated'
+ error_invalid: 'Articles are incorrect. Please check your input.'
+ error_update: "There was an error when updating the article '%{article}' on: %{msg}"
+ update_selected:
+ notice_destroy: 'All selected articles have been deleted'
+ notice_unavail: 'All selected articles have been made unavailable'
+ notice_avail: 'All selected articles have been made available '
+ notice_noaction: 'No action selected!'
+ error_nosel: 'You have selected no articles'
+ parse_upload:
+ notice: '%{count} articles analysed succesfully.'
+ error_parse: '%{msg} ... in line %{line}'
+ create_from_upload:
+ notice: '%{count} new articles were saved'
+ error_invalid: 'Articles are faulty'
+ sync:
+ shared_alert: '%{supplier} is not linked to an external database'
+ notice: 'The catalog is up to date'
+
+ # used by model
+ model:
+ error_in_use: '%{article} can not be deleted because the article is part of a current order!'
+ error_nosel: 'You have selected no articles'
diff --git a/config/locales/en/en.defaults.yml b/config/locales/en/en.defaults.yml
new file mode 100644
index 00000000..ca4b436c
--- /dev/null
+++ b/config/locales/en/en.defaults.yml
@@ -0,0 +1,320 @@
+en:
+ orders:
+ state:
+ open: open
+ finished: finished
+ closed: closed
+
+ group_orders:
+ messages:
+ not_enough_apples: >
+ You need at least %{stop_ordering_under} apples to order.
+ Currently your order group has only %{apples} apples.
+ views:
+ pagination:
+ first: "«"
+ last: "»"
+ previous: "‹"
+ next: "›"
+ truncate: "..."
+
+ 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
+ errors: &errors
+ general: 'A problem has occured.'
+ general_msg: 'A problem has occured: %{msg}'
+ general_again: 'A problem has occured. Please try again.'
+ format: ! '%{attribute} %{message}'
+ 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.'
+ 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: ''
+ support:
+ array:
+ last_word_connector: ! ' and '
+ two_words_connector: ! ' and '
+ words_connector: ! ', '
+ 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
+ # remove these aliases after 'activemodel' and 'activerecord' namespaces are removed from Rails repository
+ activemodel:
+ errors:
+ <<: *errors
+ activerecord:
+ errors:
+ <<: *errors
+ has_many_left: 'is still associated with a %{collection}!'
+ models:
+ article: Article
+ supplier: Supplier
+ user: User
+ workgroup: Workgroup
+ ordergroup: Ordergroup
+ task: Task
+ message: Message
+ article_category: Article category
+ stock_article: Stock article
+ delivery: Delivery
+ stock_taking: Stock taking
+ financial_transaction: Financial transaction
+ order: Order
+ order_comment: Order comment
+ order_article: Order article
+ invoice: Invoice
+ attributes:
+ article:
+ availability: 'Is article available?'
+ price: price
+ gross_price: gross price
+ unit: unit
+ unit_quantity: unit quantity
+ tax: VAT
+ deposit: deposit
+ article_category: article category
+ stock_article:
+ price: Price
+ user:
+ password: Password
+ first_name: First name
+ financial_transaction:
+ amount: amount
+ note: note
+
+ # messages in model that don't have a corresponding view
+ model:
+ membership:
+ no_admin_delete: 'Membership can not be withdrawn as you are the last administrator.'
+ order_article:
+ error_price: 'must be specified and have a current price price'
+ page:
+ redirect: 'Redirect to [[%{title}]]...'
+ user:
+ notify:
+ order_finished: 'Inform me about my order result (when the order is closed).'
+ negative_balance: 'inform me when by order group has a negative balance.'
+ upcoming_tasks: 'Remind me of upcoming tasks.'
+ send_as_email: 'Receive messages as emails.'
+ phone_is_public: 'Phone number is visible for other members.'
+ email_is_public: 'Email is visible for other members.'
+ name_is_public: 'Name is visible for other members.'
+ no_ordergroup: 'no order group'
+
+ helpers:
+ select:
+ prompt: please select
+ submit:
+ create: "save %{model}"
+ update: "save changes"
+ message:
+ create: 'send message'
+ invite:
+ create: send invitation
+ application:
+ sort_by: 'Sort by %{text}'
+ edit_user: 'Edit user'
+ show_google_maps: 'Show it on Google maps'
+ # long names in simple_form.labels.workgroup
+ role_admin: 'Admin'
+ role_finance: 'Finance'
+ role_suppliers: 'Suppliers'
+ role_article_meta: 'Articles'
+ role_orders: 'Orders'
+ write_message: 'Write message'
+ deliveries:
+ show_invoice: 'Show invoice'
+ new_invoice: 'New invoice'
+ orders:
+ order_pdf: 'Create PDF'
+ option_choose: 'Choose supplier/stock'
+ option_stock: 'Stock'
+ tasks:
+ required_users: '%{count} members are still needed!'
+
+ lib:
+ order_pdf:
+ page: 'Page %{number}'
+
+ # general user-interface
+ ui:
+ close: 'Close'
+ edit: 'Edit'
+ delete: 'Delete'
+ show: 'Show'
+ save: 'Save'
+ or_cancel: 'or cancel'
+ marks:
+ close: '×'
diff --git a/config/locales/en/en.deliveries.yml b/config/locales/en/en.deliveries.yml
new file mode 100644
index 00000000..b29eb383
--- /dev/null
+++ b/config/locales/en/en.deliveries.yml
@@ -0,0 +1,42 @@
+en:
+ deliveries:
+ suppliers_overview: 'Supplier overview'
+ invoice_amount: 'Invoice amount'
+ invoice_net_amount: 'Invoice net amount'
+ edit:
+ title: 'Edit suppliers'
+ form:
+ remove_article: 'Remove article from delivery'
+ add_article: 'Add stock article to delivery'
+ note_new_article: 'When an article is not yet in the inventory, you have to %{new_link} it first.'
+ note_new_article_link: 'create'
+ new_article:
+ title: 'Create new stock article'
+ search: 'Search for articles in the %{supplier} catalogue'
+ index:
+ title: '%{supplier}/deliveries'
+ confirm_delete: 'Are you sure?'
+ new_delivery: 'Create new delivery for %{supplier} '
+ new:
+ title: 'New delivery from %{supplier}'
+ show:
+ title: 'Show delivery'
+ title_articles: 'Article'
+ article: 'Article'
+ unit: 'Unit'
+ amount: 'Amount'
+ price: 'Netprice'
+ sum: 'Sum'
+ sum_net: 'Net sum'
+ sum_gross: 'Gross sum'
+ sum_diff: 'Gross - adjusted invoice ammount'
+ stock_change:
+ remove_article: 'Remove articles from delivery'
+
+ # used by controller
+ create:
+ notice: 'Delivery was created. Please don’t forget to create invoice!'
+ update:
+ notice: 'Delivery was updated.'
+ destroy:
+ notice: 'Delivery was deleted.'
diff --git a/config/locales/en/en.documents.yml b/config/locales/en/en.documents.yml
new file mode 100644
index 00000000..ae6bf922
--- /dev/null
+++ b/config/locales/en/en.documents.yml
@@ -0,0 +1,41 @@
+en:
+ # for app/documents
+ documents:
+ order_by_articles:
+ filename: 'Order %{name}-%{date} - by articles'
+ title: 'Order sorted by articles: %{name}, closed at %{date}'
+ rows:
+ - Order group
+ - Amount
+ - Price
+ order_by_groups:
+ filename: 'Order %{name}-%{date} - by group'
+ title: 'Order sorted by group: %{name}, closed at %{date}'
+ rows:
+ - Article
+ - Amount
+ - Price
+ - Unit Quantity
+ - Unit
+ - Sum
+ sum: 'Sum'
+ order_fax:
+ filename: 'Order %{name}-%{date} - Fax'
+ rows:
+ - Order Number
+ - Amount
+ - Name
+ - Barrel
+ - Unit
+ - Price/Unit
+ order_matrix:
+ filename: 'Order %{name}-%{date} - sorting matrix'
+ title: 'Order sorting matrix: %{name}, closed at %{date}'
+ heading: 'Article overview'
+ total: '%{count} articles in total'
+ rows:
+ - Article
+ - Unit
+ - Barrel
+ - FC-Price
+ - Amount
diff --git a/config/locales/en/en.feedback.yml b/config/locales/en/en.feedback.yml
new file mode 100644
index 00000000..72035d55
--- /dev/null
+++ b/config/locales/en/en.feedback.yml
@@ -0,0 +1,9 @@
+en:
+ feedback:
+ create:
+ notice: 'Your feedback was sent successfully. Thanks a lot!'
+ new:
+ title: 'Give feedback'
+ first_paragraph: 'Found a bug? Suggestions? Ideas? Reviews? We are happy to hear any feedback.'
+ second_paragraph: 'Please be aware that the Foodsoft Team is only responsible for the maintenance of the software. For questions regarding the organisation of your Foodcoop, please contact the appropriate contact person.'
+ send: 'Send'
diff --git a/config/locales/en/en.finance.yml b/config/locales/en/en.finance.yml
new file mode 100644
index 00000000..170c31f0
--- /dev/null
+++ b/config/locales/en/en.finance.yml
@@ -0,0 +1,170 @@
+en:
+ finance:
+ index:
+ title: 'Finances'
+ unpaid_invoices: 'Unpaid invoices'
+ show_all: 'Show all'
+ date: 'Date'
+ amount: 'Amount'
+ supplier: 'supplier'
+ last_transactions: 'Last Transactions'
+ group: 'Group'
+ note: 'Note'
+ open_transactions: 'Open Transactions'
+ end: 'End'
+ amount_fc: 'Amount(FC)'
+ clear: 'To account'
+ everything_cleared: 'Great, everything is accounted...'
+ balancing:
+ close:
+ notice: 'Order was accounted succesfully, the balance of the account was updated.'
+ alert: 'An error occured while accounting: %{message}'
+ close_direct:
+ notice: 'Order was closed'
+ alert: 'Order can not be closed: %{message}'
+ index:
+ title: 'Closed Orders'
+ new:
+ alert: 'Attention, order was already accounted'
+ title: 'Accounting %{name}'
+ summary: 'Summary'
+ invoice: 'Invoice'
+ notes_and_journal: 'Notes/Protocol'
+ comment_on_transaction: 'Here you can add a comment with your accounting'
+ edit_note: 'Edit note'
+ comments: 'Comments'
+ create_invoice: 'Create invoice'
+ confirm_order: 'Close order'
+ view_options: 'Viewing options'
+ edit_order: 'Edit order'
+ groups_overview: 'Overview of groups'
+ articles_overview: 'Overview of articles'
+ confirm:
+ title: 'Close order'
+ first_paragraph: 'When the order is closed, all group accounts will be updated. The accounts will be charged as follows:'
+ clear: 'Close'
+ or_cancle: 'or back to accounting'
+ summary:
+ duration: 'From %{starts} till %{ends}'
+ net_amount: 'Net amount:'
+ gross_amount: 'Gross amount:'
+ fc_amount: 'FC-amount:'
+ groups_amount: 'Group amounts:'
+ fc_profit: 'FC Profit'
+ without_extra_charge: 'Without extra charge:'
+ with_extra_charge: 'With extra charge:'
+ changed: 'Data was changed!'
+ reload: 'Reload summary'
+ orders:
+ name: 'Name'
+ end: 'End'
+ state: 'State'
+ last_edited_by: 'Last edited by'
+ cleared: 'Accounted (%{amount})'
+ clear: 'Accounting'
+ close: 'Close directly'
+ confirm: 'Really want to put the order on closed?'
+ no_closed_orders: 'At the moment there are not closed orders'
+ order_article:
+ confirm: 'Are you sure?'
+ invoice:
+ invoice_number: 'Invoice number:'
+ invoice_date: 'Invoice date:'
+ invoice_amount: 'Invoice amount:'
+ minus_refund_calculated: '- refund calculated:'
+ plus_refund_credited: '+ refund credited:'
+ refund_adjusted_amount: 'refund adjusted amount:'
+ edit: 'Edit invoice'
+ new: 'Create new invoice'
+ group_order_articles:
+ group: 'Group'
+ units: 'Units'
+ total: 'Total costs'
+ add_group: 'Add group'
+ total_fc: 'Sum (FC-Price)'
+ edit_results_by_articles:
+ article: 'Article'
+ number: 'Number'
+ amount: 'Amount'
+ amount_per_unit: 'Unit quantity'
+ net: 'Net'
+ gross: 'Gross'
+ tax: 'Tax'
+ refund: 'Refund'
+ add_article: 'Add article'
+ financial_transactions:
+ create:
+ notice: "The Transaction was saved."
+ create_collection:
+ notice: "All Transactions were saved."
+ alert: "An Error occured: %{error}"
+ ordergroup:
+ remove: "Remove"
+ remove_group: "Remove group"
+ transactions:
+ date: "Date"
+ who: "Who"
+ note: "Note"
+ amount: "Amount"
+ index:
+ title: "Account statement for %{name}"
+ new_transaction: 'Create new transaction'
+ balance: 'Balance of account: %{balance}'
+ last_updated_at: '(last updated at %{when})'
+ search_placeholder: 'Search ..'
+ new_collection:
+ title: "Updating more accounts"
+ sidebar: 'Here you can update more accounts at the same time. For example all transfers of the order group from one account statement'
+ new_ordergroup: 'Add new order group'
+ ordergroup: 'Order group'
+ note: 'Note'
+ amount: 'Amount'
+ save: "Save transaction"
+ new:
+ title: "New transaction"
+ paragraph: 'Here you can credit/deduct the order group %{name} money.'
+ group_order_articles:
+ form:
+ amount_change_for: 'Change amount for %{article}'
+ ordergroups:
+ ordergroups:
+ name: "Name"
+ account_balance: "Account Balance"
+ new_transaction: "New transaction"
+ account_statement: "Account statement"
+ index:
+ title: "Manage accounts"
+ new_transaction: "Add new transactions"
+ search_placeholder: 'Search ..'
+ invoices:
+ edit:
+ title: "Edit invoice"
+ form:
+ linked: "This invoice is linked to a %{what_link}."
+ delivery: "delivery"
+ order: "order"
+ index:
+ title: "Invoices"
+ action_new: "Create new invoice"
+ invoices:
+ delivery: "Delivery"
+ confirm_delete: "Are you sure?"
+ new:
+ title: "Create new invoice"
+ back: "Back"
+ show:
+ title: "Invoice %{number}"
+ linked: "This invoice is linked to a %{what_link}."
+ delivery: "delivery"
+ back: "Back"
+ order_articles:
+ edit:
+ title: 'Update article'
+ new:
+ title: 'Add delivered article to order'
+
+ # used by controller
+ create:
+ notice: 'Invoice was created'
+ update:
+ notice: 'Invoice was updated'
diff --git a/config/locales/en/en.foodcoop.yml b/config/locales/en/en.foodcoop.yml
new file mode 100644
index 00000000..3ee71dfc
--- /dev/null
+++ b/config/locales/en/en.foodcoop.yml
@@ -0,0 +1,34 @@
+en:
+ foodcoop:
+ ordergroups:
+ index:
+ title: 'Ordergroups'
+ name: Name ...
+ only_active: 'Only active groups'
+ only_active_desc: '(have placed order at least once in the last 3 months)'
+ ordergroups:
+ name: 'Name'
+ user: 'Users'
+ last_ordered: 'Last ordered'
+ users:
+ index:
+ title: 'Users'
+ body: >
+ Here you can write a message to the members of your Foodcoop.
+ You have to approve in your %{profile_link} that your contact details are visible.
+ profile_link: 'options'
+ ph_name: Name ...
+ ph_ordergroup: Order group ...
+ workgroups:
+ index:
+ title: 'Working groups'
+ body: >
+ Editing a group is only available to members of the group.
+ If you want to join a group, please send the members a message.
+ edit:
+ title: 'Edit group'
+ invite_new: 'You can invite new members %{invite_link}.'
+ invite_link: 'here'
+ workgroup:
+ show_tasks: 'Show all tasks'
+ edit: 'Edit group'
diff --git a/config/locales/en/en.group_orders.yml b/config/locales/en/en.group_orders.yml
new file mode 100644
index 00000000..c04257c6
--- /dev/null
+++ b/config/locales/en/en.group_orders.yml
@@ -0,0 +1,97 @@
+en:
+ group_orders:
+ archive:
+ title: 'Orders of %{group}'
+ desc: 'View all %{link} here.'
+ open_orders: 'current orders'
+ title_open: 'Completed/not accounted'
+ title_closed: 'Accounted'
+ form:
+ title: 'Orders'
+ note: 'Note'
+ created_by: 'Created by'
+ ending: 'End'
+ min_quantity: 'Minimum quantity'
+ sum_amount: 'Current amount'
+ last_update: 'Last ordered'
+ funds: 'Credit'
+ name: 'Mame'
+ price: 'Price'
+ unit: 'Unit'
+ unit_missing: 'Missing units'
+ amount: 'Amount'
+ tolerance: 'Tolerance'
+ available: 'Available'
+ sum: 'Sum'
+ units: 'Units'
+ units_full: 'Filled units'
+ total_units: 'Total units'
+ total_tolerance: 'Total tolerance'
+ manufacturer: 'Manufacturer'
+ total_sum_amount: 'Total amount'
+ available_funds: 'Available credits'
+ new_funds: 'New account balance'
+ action_save: 'Save order'
+ index:
+ title: 'Orders overview'
+ funds:
+ title: 'Credit'
+ account_balance: 'Account balance'
+ open_orders: 'Current orders'
+ finished_orders: 'Unaccounted orders'
+ available_funds: 'Available credit'
+ finished_orders:
+ title: 'Unaccounted orders'
+ total_sum: 'Total sum'
+ closed_orders:
+ title: 'Closed orders'
+ more: 'more..'
+ order:
+ title: 'Articles'
+ # other fields reference group_orders.form
+ orders: &orders
+ supplier: 'Suppliers'
+ ending: 'End'
+ sum: 'Sum'
+ show:
+ <<: *orders
+ title: 'Your order result for %{order}'
+ note: 'Note'
+ order_sum: 'Order sum'
+ not_ordered: 'You didn’t order'
+ closed_by: 'Accounted by %{user}'
+ comment: 'Comment'
+ articles:
+ title: 'Article overview'
+ show_hide: 'Show/hide articles not ordered'
+ edit_order: 'Edit order'
+ name: 'Name'
+ units: 'Units'
+ unit_price: 'Unit price'
+ ordered: 'Ordered'
+ ordered_title: 'Amount + tolerance'
+ order_open: 'Available' # or 'order open'?
+ order_not_open: 'Received' # or 'order not open'?
+ order_nopen_title: 'Considering current orders of all groups' # can this be simpler?
+ total_price: 'Total price'
+ sum: 'Sum'
+ not_ordered_msg: 'You didn’t place an order yet'
+ order_now: 'This is your chance!'
+ order_closed_msg: 'Sorry, this order is closed.'
+ comments:
+ title: 'Comments'
+ switch_order:
+ title: 'Current orders'
+ remaining: '%{remaining} remaining'
+
+ # used by controller
+ create: &create
+ notice: 'The order was saved.'
+ error_stale: "Someone else has ordered in the meantime, couldn't update the order."
+ error_general: "The order couldn’t be updated due to a bug."
+ update:
+ <<: *create
+ errors:
+ no_member: 'You are not a member of an order group.'
+ closed: 'This order is already closed.'
+ notfound: 'Incorrect URL, this is not your order.'
diff --git a/config/locales/en/en.home.yml b/config/locales/en/en.home.yml
new file mode 100644
index 00000000..27deca64
--- /dev/null
+++ b/config/locales/en/en.home.yml
@@ -0,0 +1,84 @@
+en:
+ home:
+ index:
+ title: 'Homepage'
+ your_tasks: 'Your tasks'
+ due_date_format: '%A %d %b'
+ tasks_move:
+ title: 'Take over tasks'
+ desc: 'You are responsible for these tasks.'
+ action: 'Take over tasks/decline tasks'
+ tasks_open:
+ title: 'Open tasks'
+ desc: 'There is/are %{size}'
+ action: 'open task(s)'
+ ordergroup:
+ title: 'Engagement of your ordergroup'
+ messages:
+ title: 'Newest Messages'
+ view_all: 'See all messages'
+ my_ordergroup:
+ title: 'My ordergroup'
+ funds: '| Available Credit:'
+ last_update: 'Last Update was %{when} ago'
+ transactions:
+ title: 'Last Transactions'
+ when: 'When'
+ where: 'Who'
+ note: 'Note'
+ amount: 'Amount'
+ view: 'Show account statement'
+
+ start_nav:
+ title: 'Directly to ...'
+ foodcoop: 'Foodcoop'
+ members: 'Members'
+ tasks: 'My tasks'
+ write_message: 'Write message'
+ orders:
+ title: 'Orders'
+ overview: 'Overview of orders'
+ end: 'Close orders'
+ products:
+ title: 'Products'
+ edit: 'Update products'
+ edit_stock: 'Edit stock'
+ edit_suppliers: 'Edit suppliers'
+ finances:
+ title: 'Finances'
+ accounts: 'Update accounts'
+ settle: 'To account orders'
+ admin: 'Administration'
+ new_ordergroup: 'New ordergroup'
+ new_user: 'New member'
+
+ apple_bar:
+ points: 'Your current apple points: %{points}'
+ desc: 'This shows the proportion of completed tasks to the volume of orders for your ordergroup in comparison to the average of the Foodcoop. In practice: for every %{amount} of total orders, you should execute a task!'
+ warning: 'Warning, if you have less then %{threshold} of apple points, you are not allowed to place an order!'
+ more_info: 'More information'
+
+ ordergroup:
+ title: 'My ordergroup'
+ description: 'description'
+ funds: 'Available credit:'
+ people: 'People'
+ invite: 'Invite a new Person'
+ account_summary: 'Account Statement'
+ search: Search ...
+
+ profile:
+ title: 'My Profile'
+ user:
+ title: '%{user}'
+ since: '(member since: %{when})'
+ groups:
+ title: 'You are member of the following groups'
+ invite: 'Invite new members'
+ cancel: 'Leave group'
+ cancel_confirm: 'Are you sure you want to leave this group?'
+
+ # used by controller
+ changes_saved: 'Changes saved.'
+ no_ordergroups: 'You are unfortunately not a member of an ordergroup.'
+ ordergroup_cancelled: 'You cancelled membership of the group %{group}.'
diff --git a/config/locales/en/en.invites.yml b/config/locales/en/en.invites.yml
new file mode 100644
index 00000000..0c125aaf
--- /dev/null
+++ b/config/locales/en/en.invites.yml
@@ -0,0 +1,18 @@
+en:
+ invites:
+ new:
+ body: Here you can add a person to the group %{group} , who is not yet a member of the foodcoop.
+ action: 'Send invite'
+ back: 'or go back'
+ modal_form:
+ title: 'Invite person'
+ body: >
+ Here you can invite a person to a group %{group} , who is not yet a member of the foodcoop.
+ After being added for the first time, the person is automatically a member of this group.
+
+ # used by controller
+ success: 'User was invited successfully.'
+
+ # used by model
+ errors:
+ already_member: 'is already in use. Person is already a member of this Foodcoop.'
diff --git a/config/locales/en/en.layouts.yml b/config/locales/en/en.layouts.yml
new file mode 100644
index 00000000..3709a05d
--- /dev/null
+++ b/config/locales/en/en.layouts.yml
@@ -0,0 +1,21 @@
+en:
+ layouts:
+ foodsoft: 'Foodsoft'
+ logo: 'food soft'
+ header:
+ profile: 'Edit profile'
+ ordergroup: 'My ordergroup'
+ logout: 'Logout'
+ help: 'Help'
+ feedback:
+ title: 'Feedback'
+ desc: 'Found a bug? Suggestions? Ideas? Review?'
+ footer: 'Foodsoft, open source software to manage a non-profit food coop.'
+ email:
+ footer: |
+ --
+ Foodsoft: %{foodsoft}
+ Foodcoop-Homepage: %{foodcoop}
+ Help: %{help}
+ application1:
+ title: 'Foodsoft - %{title}'
diff --git a/config/locales/en/en.login.yml b/config/locales/en/en.login.yml
new file mode 100644
index 00000000..ac73dfbf
--- /dev/null
+++ b/config/locales/en/en.login.yml
@@ -0,0 +1,38 @@
+en:
+ login:
+ accept_invitation:
+ title: 'Invitation to %{name}'
+ body: >
+ You are invited to be part of the foodcoop %{foodcoop} as
+ a member of the group %{group} .
+ If you want to participate, please fill in this form.
+ Naturally, your information wll not be shared with third parties for
+ any reason. You can decide how much of your personal information
+ should be visible for everyone. 'All' means all Foodcoop-members.
+ Please note that the administrators do have access to your information.
+ submit: 'Create a Foodsoft account'
+ forgot_password:
+ title: 'Forgot password?'
+ body: >
+ No Problem, you can choose a new password.
+ Please fill in the email address with which you are registered here.
+ Then you will receive an email with further instructions.
+ submit: 'Request new password'
+ new_password:
+ title: 'New password'
+ body: >
+ Please fill in the new password for %{user}
+ submit: 'Save new password'
+
+ # used by controller
+ controller:
+ reset_password:
+ notice: 'If your email is registered here, you will receive a message with a link to reset your password.'
+ update_password:
+ notice: 'Your password was updated. You can login now.'
+ accept_invitation:
+ notice: 'Congratulations, your account was created. You can login now.'
+ error_invite_invalid: 'Your invite is not valid (anymore).'
+ error_group_invalid: 'The group in which you were invited doesn’t exist anymore.'
+ error_token_invalid: 'Invalid or expired token. Please try again.'
+
diff --git a/config/locales/en/en.mailer.yml b/config/locales/en/en.mailer.yml
new file mode 100644
index 00000000..e098a981
--- /dev/null
+++ b/config/locales/en/en.mailer.yml
@@ -0,0 +1,81 @@
+en:
+ mailer:
+ dateformat: '%d %b'
+ feedback:
+ subject: 'Feedback from %{email}'
+ header: '%{user} wrote at %{date}:'
+ foodsoft_message:
+ footer: |
+ Reply: %{reply_url}
+ See message online: %{msg_url}
+ Messaging options: %{profile_url}
+ invite:
+ subject: 'Invitation to the Foodcoop'
+ text: |
+ Hi!
+
+ %{user} <%{mail}> has invited you to join the group "%{group}".
+ To accept the invitation and to join the foodcoop please follow this link: %{link}
+ This link works only once and expires on %{expires}.
+
+ Greetings, your Foodsoft Team!
+ negative_balance:
+ subject: 'Negative account balance'
+ text: |
+ Dear %{group},
+
+ Your account balance has dropped below zero due to a booking on %{when}: %{balance}
+
+ There was a charge of %{amount} for "%{note}" by %{user}.
+
+ Please deposit your account as soon as possible.
+
+ Kind regards from %{foodcoop}.
+ not_enough_users_assigned:
+ subject: '"%{task}" still needs people!'
+ text: |
+ Dear %{user},
+
+ The Task '%{task}' of your working group is due on %{when},
+ and could use some more contributors!
+
+ If you haven’t assigned yourself to this task yet it’s your chance now:
+
+ %{workgroup_tasks_url}
+
+ Your Tasks: %{user_tasks_url}
+ order_result:
+ text0: |
+ Dear %{ordergroup},
+
+ The order for "%{order}" was placed on %{when} by %{user}.
+
+ The following articles were ordered by your ordergroup:
+ text1: |
+ Total sum: %{sum}
+
+ See order online: %{order_url}
+
+ Kind regards from %{foodcoop}.
+ reset_password:
+ subject: 'New password for %{username}'
+ text: |
+ Hi %{user},
+
+ You have (or someone else has) requested a new password.
+ In order to choose a new password follow this link: %{link}
+ This link works only once and expires on %{expires}.
+ If you don't want to change your password, just ignore this message. Your password hasn't been changed yet.
+
+ Greetings, your Foodsoft Team!
+ upcoming_tasks:
+ subject: 'Tasks are due!'
+ text0: |
+ Dear %{user},
+
+ You are asigned to the task "%{task}". This task is due by tomorrow (%{when})!
+ nextweek: 'Tasks for the next week:'
+ text1: |
+ My tasks: %{user_tasks_url}
+
+ Kind regards from %{foodcoop}.
diff --git a/config/locales/en/en.messages.yml b/config/locales/en/en.messages.yml
new file mode 100644
index 00000000..f4469fd6
--- /dev/null
+++ b/config/locales/en/en.messages.yml
@@ -0,0 +1,36 @@
+en:
+ messages:
+ index:
+ title: 'Messages'
+ new: 'New message'
+ messages:
+ reply: 'Reply'
+ new:
+ title: 'New message'
+ search_user: 'Search user'
+ no_user_found: 'No user found'
+ search: 'Search ...'
+ list:
+ desc: 'Please send messages to all using the mailing-list: %{list}'
+ subscribe_msg: 'You may have to subscribe to the mailing-list first.'
+ subscribe: 'You can find more about the mailing-list at %{link}.'
+ wiki: 'Wiki (page Mailing-List)'
+ mail: 'for example with an email to %{email}.'
+ cancel: 'or cancel'
+ show:
+ title: 'Show message'
+ from: 'From:'
+ subject: 'Subject:'
+ sent_on: 'Sent:'
+ reply: 'Reply'
+ all_messages: 'All messages'
+
+ # used by controller
+ create:
+ notice: 'Message is saved and will be sent.'
+
+ # used by model
+ model:
+ reply_subject: 'Re: %{subject}'
+ reply_header: '%{user} wrote on %{when}:'
+ reply_indent: '> %{line}'
diff --git a/config/locales/en/en.navigation.yml b/config/locales/en/en.navigation.yml
new file mode 100644
index 00000000..c2ec6934
--- /dev/null
+++ b/config/locales/en/en.navigation.yml
@@ -0,0 +1,36 @@
+en:
+ # for config/navigation.rb
+ navigation:
+ dashboard: 'Dashboard'
+ foodcoop: 'Foodcoop'
+ members: 'Members'
+ workgroups: 'Workgroups'
+ ordergroups: 'Ordergroups'
+ messages: 'Messages'
+ tasks: 'Tasks'
+ wiki:
+ title: 'Wiki'
+ home: 'Home'
+ all_pages: 'All Pages'
+ orders:
+ title: 'Orders'
+ ordering: 'Place order!'
+ archive: 'My Orders'
+ manage: 'Manage orders'
+ articles:
+ title: 'Articles'
+ suppliers: 'Suppliers/articles'
+ stock: 'Stock'
+ categories: 'Categories'
+ finances:
+ title: 'Finances'
+ home: 'Overview'
+ accounts: 'Manage accounts'
+ balancing: 'Account orders'
+ invoices: 'Invoices'
+ admin:
+ title: 'Administration'
+ home: 'Overview'
+ users: 'Users'
+ ordergroups: 'Ordergroups'
+ workgroups: 'Workgroups'
diff --git a/config/locales/en/en.ordergroups.yml b/config/locales/en/en.ordergroups.yml
new file mode 100644
index 00000000..e18e150a
--- /dev/null
+++ b/config/locales/en/en.ordergroups.yml
@@ -0,0 +1,11 @@
+en:
+ ordergroups:
+ index:
+ title: 'Ordergroups'
+ edit:
+ title: 'Edit ordergroups'
+
+ # used by model
+ model:
+ invalid_balance: 'is not a valid number'
+ error_single_group: '%{user} is already a member of another ordergroup'
diff --git a/config/locales/en/en.orders.yml b/config/locales/en/en.orders.yml
new file mode 100644
index 00000000..9dd2080e
--- /dev/null
+++ b/config/locales/en/en.orders.yml
@@ -0,0 +1,86 @@
+en:
+ orders:
+ articles:
+ name: 'Name'
+ unit_quantity: 'Unit quantity'
+ prices: 'Net/gross price'
+ units_ordered: 'Units ordered'
+ units_full: 'Full units'
+ prices_sum: 'Sum (net/gross price):'
+ article_count: 'Ordered articles:'
+ edit:
+ title: 'Edit order'
+ new:
+ title: 'Create new order'
+ form:
+ title: 'Article'
+ name: 'Name'
+ note: 'Note'
+ stockit: 'In stock'
+ origin: 'Origin'
+ supplier: 'Supplier'
+ unit_quantity: 'Unit quantity'
+ prices: 'Prices (net/FC)'
+ select_all: 'Select all'
+ index:
+ title: 'Manage orders'
+ new_order: 'Create new order'
+ open_orders: 'Current orders'
+ supplier: 'Supplier'
+ ending: 'End'
+ note: 'Note'
+ action_end: 'Close'
+ confirm_end: 'Do you really want to close the order %{order}? There is no going back.'
+ confirm_delete: 'Do you really want to delete the order?'
+ no_open_orders: 'There are no current orders.'
+ ended_orders: 'Closed orders'
+ orders:
+ supplier: 'Supplier'
+ start: 'Start'
+ ending: 'End'
+ status: 'Status'
+ show:
+ title: 'Order: %{name}'
+ warn_not_closed: 'Warning, order is not accounted yet.'
+ supplier: 'Supplier:'
+ note: 'Note:'
+ created_by: 'Created by:'
+ begin: 'Begin:'
+ ending: 'End:'
+ group_orders: 'Group orders:'
+ amounts: 'Net/gross sum:'
+ articles_ordered: 'Ordered articles:'
+ action_end: 'Close!'
+ confirm_end: "Do you really want to close the order %{order}?\nThere is no going back."
+ confirm_delete: 'Do you really want to delete the order?'
+ articles: 'Article overview'
+ sort_group: 'Sorted in groups'
+ sort_article: 'Sorted in articles'
+ comments_link: 'Comments'
+ download:
+ title: 'Download'
+ group_pdf: 'Group PDF'
+ article_pdf: 'Article PDF'
+ matrix_pdf: 'Matrix PDF'
+ fax_pdf: 'Fax PDF'
+ fax_txt: 'Fax text'
+ download_file: 'Download file'
+ comments:
+ title: 'Comments'
+
+ # used by controller
+ create:
+ notice: 'The order was created.'
+ update:
+ notice: 'The order was updated.'
+ finish:
+ notice: 'The order has finished.'
+ fax:
+ heading: 'Order for %{name}'
+ customer_number: 'Customer number'
+ delivery_day: 'Delivery day'
+ to_address: 'Shipping address'
+ articles: 'Articles'
+ number: 'Number'
+ amount: 'Amount'
+ name: 'Name'
diff --git a/config/locales/en/en.pages.yml b/config/locales/en/en.pages.yml
new file mode 100644
index 00000000..73d1fa98
--- /dev/null
+++ b/config/locales/en/en.pages.yml
@@ -0,0 +1,73 @@
+en:
+ pages:
+ title: 'Title'
+ last_updated: 'Last updated'
+ all:
+ title: 'All Wiki pages'
+ new_page: 'Create new page'
+ recent_changes: 'Recent changes'
+ title_list: 'List of pages'
+ site_map: 'Sitemap'
+ search:
+ placeholder: 'Page title ..'
+ action: 'Search'
+ body:
+ title_toc: 'Content'
+ edit:
+ title: 'Edit page'
+ form:
+ preview: 'Preview'
+ help:
+ title: 'Quick formatting help'
+ section_character: 'Character formatting'
+ italic: 'italic'
+ bold: 'bold'
+ noformat: 'No wiki-formatting'
+ text: 'text'
+ section_block: 'Block formatting'
+ headings: 'Heading'
+ heading: 'level %{level}'
+ unordered_list: 'Item list'
+ list_item_1: 'First list item'
+ list_item_2: 'Secound list item'
+ ordered_list: 'Numbered list'
+ section_link: 'Link formatting'
+ wiki_links: 'Wiki-links'
+ wiki_link_ex: 'Foodsoft Wiki Page'
+ external_links: 'External links'
+ external_link_ex: 'External page'
+ section_table: 'Table formatting'
+ see_tables: 'see %{tables_link}'
+ tables_link: 'Tables'
+ new:
+ title: 'Create new wiki page'
+ page_list_item:
+ date_format: '%a, %d %B %Y %H:%M:%S'
+ show:
+ edit: 'Edit page'
+ versions: 'Versions (%{count})'
+ subpages: 'subpages'
+ title_versions: 'Versions'
+ date_format: '%d-%m-%y %H:%M'
+ delete: 'Delete page'
+ delete_confirm: 'Warning: all subpages will be deleted as well. Are you sure?'
+ last_updated: 'Last updated by %{user} on %{when}'
+ version:
+ title: '%{title} - version %{version}'
+ title_version: 'Version'
+ date_format: '%a, %d-%m-%Y, %H:%M'
+ author: 'Author: %{user}'
+ view_current: 'See current version'
+ revert: 'Revert to this version'
+
+ # used by controller
+ cshow:
+ error_noexist: 'Page doesn’t exist!'
+ redirect_notice: 'Redirected from %{page} ..'
+ create:
+ notice: 'Page was created'
+ update:
+ notice: 'Page was updated'
+ destroy:
+ notice: "The page '%{page}' and all subpages have been deleted successfully."
+ error_stale_object: 'Warning, the page has just been edited by someone else. Please try again.'
diff --git a/config/locales/en/en.sessions.yml b/config/locales/en/en.sessions.yml
new file mode 100644
index 00000000..874b6bb6
--- /dev/null
+++ b/config/locales/en/en.sessions.yml
@@ -0,0 +1,14 @@
+en:
+ sessions:
+ new:
+ title: 'Foodsoft login'
+ nojs: 'Attention, Cookies and Javascript have to be activated! Please switch off %{link}.'
+ noscript: 'NoScript'
+ user: 'User'
+ password: 'Password'
+ login: 'Login'
+ forgot_password: 'Forgot password?'
+ # used in controller
+ logged_in: 'Logged in!'
+ logged_out: 'Logged out!'
+ login_invalid: 'Invalid email or password'
diff --git a/config/locales/en/en.shared.yml b/config/locales/en/en.shared.yml
new file mode 100644
index 00000000..76574c3f
--- /dev/null
+++ b/config/locales/en/en.shared.yml
@@ -0,0 +1,68 @@
+en:
+ shared:
+ articles_by_articles:
+ ordergroup: 'Ordergroup'
+ ordered: 'Ordered (Amount + Tolerance)'
+ received: 'Received'
+ price: 'Total price'
+ articles_by_groups:
+ name: 'Name'
+ units: 'Amount'
+ units_desc: 'Assigned units'
+ fc_price: 'FC-Price'
+ fc_price_desc: 'Price including taxes, deposit and Foodcoop-charge'
+ unit_quantity: 'Lot quantity'
+ unit_quantity_desc: 'How many units per lot.'
+ unit: 'Unit'
+ price: 'Total price'
+ group_form_fields:
+ title: 'Weekly jobs'
+ search_user: 'Search user'
+ user_not_found: 'No user found'
+ search: 'Search ...'
+ group:
+ description: 'Description'
+ contact: 'Contact'
+ address: 'Address'
+ access: 'Access to'
+ members: 'Members'
+ weekly_job: 'Weekly job'
+ no_weekly_job: 'No weekly job defined'
+ apple_limit: 'Apple points order limit'
+ deactivated: 'deactivated'
+ activated: 'activated'
+ loginInfo:
+ profile: 'Profile'
+ edit_profile: 'Edit profile'
+ homepage_title: 'Visit Foodcoop Homepage'
+ # duplicate from de.layouts.header
+ logout: 'Logout'
+ help: 'Help'
+ feedback:
+ title: 'Feedback'
+ desc: 'Found a bug? Suggestions? Review?'
+ open_orders:
+ title: 'Current orders'
+ not_enough_apples: 'Attention your order group has too few apple points to place an order!'
+ supplier: 'Supplier'
+ ending: 'Ending'
+ who_ordered: 'Who ordered?'
+ total: 'Sum'
+ total_sum: 'Total sum'
+ no_open_orders: 'There are no current orders'
+ workgroup_members:
+ title: 'Group memberships'
+
+ memberships:
+ current_members:
+ drop: 'remove'
+ no_members: '%{group} has no members.'
+ members:
+ title: 'Members of %{group}'
+ desc: 'Here you can manage members of the group or invite a new Foodcoop-member to the group %{link}.'
+ invite: 'invite'
+ already_members: 'Are already members'
+ no_members_yet: 'Are not members yet'
+ invite_someone: 'Invite someone'
+ non_members:
+ add: 'add'
diff --git a/config/locales/en/en.simple_form.yml b/config/locales/en/en.simple_form.yml
new file mode 100644
index 00000000..31cc4b6c
--- /dev/null
+++ b/config/locales/en/en.simple_form.yml
@@ -0,0 +1,149 @@
+en:
+ # Simple form i18n is used to build the forms
+ simple_form:
+ "yes": 'Yes'
+ "no": 'No'
+ required:
+ text: 'required'
+ mark: '*'
+ error_notification:
+ default_message: 'Errors were found. Please check the form.'
+ labels:
+ defaults:
+ password: 'Password'
+ password_confirmation: 'Repeat password'
+ description: 'Description'
+ title: 'Title'
+ email: 'Email'
+ note: 'Note'
+ date: 'Date'
+ ordergroup: 'Ordergroup'
+ amount: 'Amount'
+ phone: 'Phone'
+ user_tokens: 'Members'
+ price: 'Price (net)'
+ unit_quantity: 'Unit quantity'
+ order_number: 'Order number'
+ tax: 'VAT'
+ deposit: 'Deposit'
+ user:
+ nick: 'Username'
+ first_name: 'First name'
+ last_name: 'Last name'
+ workgroup:
+ weekly_task: 'Define monthly task?'
+ weekday: 'Weekday'
+ task_name: 'Task name'
+ task_required_users: 'People required'
+ task_duration: 'Duration in hours'
+ task_description: 'Description'
+ next_weekly_tasks_number: 'For how many weeks in advance would you like to define tasks?'
+ role_admin: 'Administration'
+ role_finance: 'Finances'
+ role_suppliers: 'Suppliers'
+ role_article_meta: 'Article database'
+ role_orders: 'Order management'
+ ordergroup:
+ contact_person: 'Contact person'
+ contact_phone: 'Phone'
+ contact_address: 'Address'
+ ignore_apple_restriction: 'Ignore order stop by apple points restriction'
+ task:
+ name: 'Name'
+ duration: 'Duration'
+ user_list: 'Responsible user'
+ required_users: 'People required'
+ due_date: 'Due date'
+ workgroup: 'Workgroup'
+ done: 'Done?'
+ message:
+ sent_to_all: 'Send to all members'
+ recipient_tokens: 'Recipients'
+ group_id: 'Group'
+ subject: 'Subject'
+ body: 'Body'
+ private: 'Private'
+ page:
+ body: 'Body'
+ parent_id: Parent page
+ supplier:
+ name: 'Name'
+ address: 'Address'
+ phone: 'Phone'
+ phone2: 'Phone 2'
+ fax: 'Fax'
+ email: 'Email'
+ url: 'Homepage'
+ contact_person: 'Contact person'
+ customer_number: 'Customer ID'
+ delivery_days: 'Delivery days'
+ order_howto: 'How to order'
+ note: 'Note'
+ min_order_quantity: 'Minimum order quantity'
+ is_subscribed: 'subscribed?'
+ article:
+ name: 'Name'
+ origin: 'Origin'
+ manufacturer: 'Manufacturer'
+ unit: 'Unit'
+ note: 'Note'
+ article_category: 'Category'
+ article_category:
+ name: 'Name'
+ description: 'Description'
+ stock_article:
+ supplier: 'Supplier'
+ delivery:
+ supplier: 'Supplier'
+ delivered_on: 'Delivery date'
+ user:
+ nick: 'Username'
+ name: "Name"
+ last_name: 'Last name'
+ email: 'Email'
+ phone: "Telephone"
+ ordergroup: 'Ordergroup'
+ workgroup:
+ one: 'Workgroup'
+ other: 'Workgroups'
+ order_comment:
+ text: Add comment to this order ...
+ order:
+ starts: 'Starts at'
+ ends: 'Ends at'
+ order_article:
+ article_id: Choose article from the catalogue
+ group_order_article:
+ ordergroup_id: Ordergroup
+ result: Amount
+ invoice:
+ supplier: Supplier
+ number: Number
+ date: Billing date
+ paid_on: Paid on
+ deposit: Charge deposit
+ deposit_credit: Credit deposit
+ amount: Amount
+ delivery: Delivery
+ order: Order
+ note: Note
+ order_article:
+ units_to_order: Amount of units
+ update_current_price: Globally update current price
+
+ hints:
+ tax: 'In percentage, standard is 7,0'
+ task:
+ duration: 'How long will the task take, 1-3 hours'
+ required_users: 'How many users will be needed in total?'
+ supplier:
+ min_order_quantity: 'The minimum amount which has to be orderd will be shown during the order process and should motivate ordering'
+ article:
+ unit: 'For example: KG or 1L or 500g'
+ stock_article:
+ supplier: ''
+ message:
+ private: Message doesn’t show in Foodsoft mail inbox
+ order_article:
+ units_to_order: Amount of delivered units
+ update_current_price: Also update the price of the current order
diff --git a/config/locales/en/en.stock_takings.yml b/config/locales/en/en.stock_takings.yml
new file mode 100644
index 00000000..a3930b89
--- /dev/null
+++ b/config/locales/en/en.stock_takings.yml
@@ -0,0 +1,34 @@
+en:
+ stock_takings:
+ edit:
+ title: 'Edit inventory'
+ index:
+ title: 'Inventory overview'
+ new_inventory: 'Create new inventory'
+ new:
+ title: 'Create new inventory'
+ text_deviations: 'Please fill in all surplus deviations from the %{inv_link}. For reduction, use a a negative number.'
+ temp_inventory: 'temporary inventory'
+ text_need_articles: 'You have to %{create_link} a new stock article before you can use it here.'
+ create: 'create'
+ stock_articles: 'Stock articles'
+ show:
+ title: 'Show inventory'
+ date: 'Date'
+ note: 'Note'
+ article: 'Article'
+ supplier: 'Supplier'
+ unit: 'Unit'
+ amount: 'Amount'
+ overview: 'Inventory overview'
+ confirm_delete: 'Do you really want to delete the inventory?'
+ stock_takings:
+ date: 'Date'
+ note: 'Note'
+ confirm_delete: 'Are you sure you want to delete this?'
+
+ # used by controller
+ create:
+ notice: 'Inventory was created successfully.'
+ update:
+ notice: 'Inventory was updated.'
diff --git a/config/locales/en/en.stockit.yml b/config/locales/en/en.stockit.yml
new file mode 100644
index 00000000..02ebc356
--- /dev/null
+++ b/config/locales/en/en.stockit.yml
@@ -0,0 +1,42 @@
+en:
+ stockit:
+ edit:
+ 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.'
+ index:
+ view_options: 'View options'
+ toggle_unavailable: 'Show/hide unavailable articles'
+ order_online: 'Put stock order online'
+ new_stock_article: 'Add new stock article'
+ new_stock_taking: 'Add inventory'
+ show_stock_takings: 'Inventory overview'
+ new_delivery: 'New delivery ..'
+ article:
+ article: 'Article'
+ stock: 'In stock'
+ ordered: 'ordered'
+ available: 'available'
+ unit: 'Unit'
+ price: 'Price'
+ vat: 'VAT'
+ supplier: 'Supplier'
+ category: 'Category'
+ confirm_delete: 'Are you sure you want to delete?'
+ stock_worth: 'Current stock value:'
+ stock_count: 'Number of articles:'
+ new:
+ title: 'Add new stock article'
+ search_text: 'Search for articles in all catalogues:'
+ destroy:
+ notice: 'Article %{name} was deleted.'
+
+ # used by controller
+ stock_create:
+ notice: 'Stock article was created.'
+ stock_update:
+ notice: 'Stock article was saved.'
+
+ # used by model
+ check:
+ not_empty: '%{name} could not be deleted, the inventory is not zero.'
diff --git a/config/locales/en/en.suppliers.yml b/config/locales/en/en.suppliers.yml
new file mode 100644
index 00000000..4bafbfad
--- /dev/null
+++ b/config/locales/en/en.suppliers.yml
@@ -0,0 +1,36 @@
+en:
+ suppliers:
+ shared_supplier_note: 'Supplier is connected to the external database.'
+ index:
+ title: 'Suppliers'
+ action_new: 'Create new supplier'
+ action_import: 'Import supplier from external database'
+ articles: 'articles (%{count})'
+ stock: 'in stock (%{count})'
+ deliveries: 'deliveries (%{count})'
+ confirm_del: 'Do you really want to delete the supplier %{name}?'
+ edit:
+ title: 'Edit supplier'
+ new:
+ title: 'New supplier'
+ show:
+ confirm_delete: 'Are you sure?'
+ last_deliveries: 'Last deliveries'
+ new_delivery: 'Create new delivery'
+ show_deliveries: 'Show all deliveries'
+ shared_suppliers:
+ title: 'External lists'
+ body: >
+ Suppliers of the external database are displayed here.
+ You can import external suppliers by subscribing (see below).
+ A new supplier will be created and connected to the external database.
+ supplier: 'Supplier'
+ subscribe: 'Subscribe'
+
+ # used by controller
+ create:
+ notice: 'Supplier was created'
+ update:
+ notice: 'Supplier was updated'
+ destroy:
+ notice: 'Supplier was deleted'
diff --git a/config/locales/en/en.tasks.yml b/config/locales/en/en.tasks.yml
new file mode 100644
index 00000000..09e40d37
--- /dev/null
+++ b/config/locales/en/en.tasks.yml
@@ -0,0 +1,75 @@
+en:
+ tasks:
+ archive:
+ title: 'Task archive'
+ archive_tasks:
+ due_date: 'Due date'
+ task: 'Subject'
+ who: 'People in charge'
+ task_format: '%{name} (%{duration}h)'
+ edit:
+ title: 'Edit task'
+ form:
+ search:
+ hint: "Search for user"
+ noresult: 'No user found'
+ placeholder: 'Search ...'
+ index:
+ title: 'Tasks'
+ title_non_group: 'Tasks for all!'
+ show_group_tasks: 'Show group tasks'
+ list:
+ due_date: 'Due date'
+ task: 'subject'
+ who: 'Who is doing it?'
+ who_hint: '(How much are still needed?)'
+ task_format: '%{name} (%{duration}h)'
+ accept_task: 'Accept task'
+ reject_task: 'Reject task'
+ mark_done: 'Mark task as done'
+ done_q: 'Done?'
+ done: 'Done'
+ nav:
+ new_task: 'Create new task'
+ my_tasks: 'My tasks'
+ all_tasks: 'All tasks'
+ archive: 'Completed tasks (archive)'
+ group_tasks: 'Group tasks'
+ new:
+ title: 'Create new tasks'
+ show:
+ title: 'Show task'
+ hours: '%{count}h'
+ due_date: 'Due date'
+ accept_task: 'Accept task'
+ reject_task: 'Reject task'
+ mark_done: 'Mark task as done'
+ user:
+ title: 'My tasks'
+ title_open: 'Open tasks'
+ title_accepted: 'Accepted tasks'
+ more: 'Nothing to do? %{tasks_link} are tasks for sure.'
+ tasks_link: 'Here'
+ workgroup:
+ title: 'Tasks for %{workgroup}'
+ weekly:
+ title: 'Weekly tasks'
+ desc: >
+ Every %{weekday} this workgroup has the following job: %{task}
+ The weektask has been created by Foodsoft automatically. You still have to sign up for it yourself.
+ empty: 'No weekly tasks created yet.'
+ edit: 'Edit weekly tasks'
+ title_all: 'All group tasks'
+
+ # used by controller
+ create:
+ notice: 'Task has been created'
+ update:
+ notice: 'Task has been updated'
+ destroy:
+ notice: 'Task has been deleted'
+ accept:
+ notice: 'You have accepted the task'
+ set_done:
+ notice: 'The state of the task has been updated'
+ error_not_found: 'No workgroup found'
diff --git a/config/locales/en/en.workgroups.yml b/config/locales/en/en.workgroups.yml
new file mode 100644
index 00000000..9349d92d
--- /dev/null
+++ b/config/locales/en/en.workgroups.yml
@@ -0,0 +1,12 @@
+en:
+ workgroups:
+ edit:
+ title: 'Edit workgroup'
+ index:
+ title: 'Workgroups'
+
+ # used by controller
+ update:
+ notice: 'Workgroup was updated'
+ error_last_admin_group: 'The last group with admin rights must not be deleted'
+ error_last_admin_role: 'Admin role for the last group with admin rights cannot be withdrawn'
diff --git a/config/navigation.rb b/config/navigation.rb
new file mode 100644
index 00000000..74b76bbe
--- /dev/null
+++ b/config/navigation.rb
@@ -0,0 +1,52 @@
+# -*- coding: utf-8 -*-
+# Configures your navigation
+
+SimpleNavigation::Configuration.run do |navigation|
+
+ navigation.items do |primary|
+ primary.dom_class = 'nav'
+
+ primary.item :dashboard_nav_item, I18n.t('navigation.dashboard'), root_path(anchor: '')
+
+ primary.item :foodcoop, I18n.t('navigation.foodcoop'), '#', id: nil do |subnav|
+ subnav.item :members, I18n.t('navigation.members'), foodcoop_users_path, id: nil
+ subnav.item :workgroups, I18n.t('navigation.workgroups'), foodcoop_workgroups_path, id: nil
+ subnav.item :ordergroups, I18n.t('navigation.ordergroups'), foodcoop_ordergroups_path, id: nil
+ subnav.item :messages, I18n.t('navigation.messages'), messages_path, id: nil
+ subnav.item :tasks, I18n.t('navigation.tasks'), tasks_path, id: nil
+ end
+
+ primary.item :wiki, I18n.t('navigation.wiki.title'), '#', id: nil do |subnav|
+ subnav.item :wiki_home, I18n.t('navigation.wiki.home'), wiki_path, id: nil
+ subnav.item :all_pages, I18n.t('navigation.wiki.all_pages'), all_pages_path, id: nil
+ end
+
+ primary.item :orders, I18n.t('navigation.orders.title'), '#', id: nil do |subnav|
+ subnav.item :ordering, I18n.t('navigation.orders.ordering'), group_orders_path, id: nil
+ subnav.item :ordering_archive, I18n.t('navigation.orders.archive'), archive_group_orders_path, id: nil
+ subnav.item :orders, I18n.t('navigation.orders.manage'), orders_path, if: Proc.new { current_user.role_orders? }, id: nil
+ end
+
+ primary.item :articles, I18n.t('navigation.articles.title'), '#', id: nil,
+ if: Proc.new { current_user.role_article_meta? or current_user.role_suppliers? } do |subnav|
+ subnav.item :suppliers, I18n.t('navigation.articles.suppliers'), suppliers_path, id: nil
+ subnav.item :stockit, I18n.t('navigation.articles.stock'), stock_articles_path, id: nil
+ subnav.item :categories, I18n.t('navigation.articles.categories'), article_categories_path, id: nil
+ end
+
+ primary.item :finance, I18n.t('navigation.finances.title'), '#', id: nil, if: Proc.new { current_user.role_finance? } do |subnav|
+ subnav.item :finance_home, I18n.t('navigation.finances.home'), finance_root_path
+ subnav.item :accounts, I18n.t('navigation.finances.accounts'), finance_ordergroups_path, id: nil
+ subnav.item :balancing, I18n.t('navigation.finances.balancing'), finance_order_index_path, id: nil
+ subnav.item :invoices, I18n.t('navigation.finances.invoices'), finance_invoices_path, id: nil
+ end
+
+ primary.item :admin, I18n.t('navigation.admin.title'), '#', id: nil, if: Proc.new { current_user.role_admin? } do |subnav|
+ subnav.item :admin_home, I18n.t('navigation.admin.home'), admin_root_path
+ subnav.item :users, I18n.t('navigation.admin.users'), admin_users_path, id: nil
+ subnav.item :ordergroups, I18n.t('navigation.admin.ordergroups'), admin_ordergroups_path, id: nil
+ subnav.item :workgroups, I18n.t('navigation.admin.workgroups'), admin_workgroups_path, id: nil
+ end
+ end
+
+end
diff --git a/config/routes.rb b/config/routes.rb
index 3c70774f..cbcf2828 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -1,80 +1,190 @@
-ActionController::Routing::Routes.draw do |map|
+Foodsoft::Application.routes.draw do
- # Use routing filter to select foodcoop config and datbase
- map.filter 'foodcoop', :file => File.join(RAILS_ROOT, "lib", "foodcoop_filter")
+ get "order_comments/new"
- # Root path
- map.root :controller => 'home', :action => 'index'
+ get "comments/new"
- # User specific
- map.login "/login", :controller => 'login', :action => 'index'
- map.logout '/logout', :controller => 'login', :action => 'logout'
- map.my_profile '/home/profile', :controller => 'home', :action => 'profile'
- map.my_ordergroup '/home/ordergroup', :controller => 'home', :action => 'ordergroup'
+ get "sessions/new"
- # Wiki
- map.resources :pages, :collection => { :all => :get }, :member => {:version => :get, :revert => :get}
- map.wiki_page "/wiki/:permalink", :controller => 'pages', :action => 'show', :permalink => /[^\s]+/
- map.wiki "/wiki", :controller => 'pages', :action => 'show', :permalink => 'Home'
+ root :to => redirect("/#{FoodsoftConfig.scope}")
- # Orders, ordering
- map.resources :orders, :member => { :finish => :post, :add_comment => :post }
- map.with_options :controller => "ordering" do |ordering|
- ordering.ordering "/ordering", :action => "index"
- ordering.my_orders "/ordering/myOrders", :action => "myOrders"
- end
+ scope '/:foodcoop' do
+ # Root path
+ root :to => 'home#index'
- # Foodcoop orga
- map.resources :invites, :only => [:new, :create]
- map.resources :tasks,
- :collection => {:user => :get, :archive => :get, :workgroup => :get}
- map.resources :messages, :only => [:index, :show, :new, :create],
- :member => { :reply => :get, :user => :get, :group => :get }
- map.namespace :foodcoop do |foodcoop|
- foodcoop.root :controller => "users", :action => "index"
- foodcoop.resources :users, :only => [:index]
- foodcoop.resources :ordergroups, :only => [:index]
- foodcoop.resources :workgroups, :only => [:index, :edit, :update],
- :member => {:memberships => :get}
- end
+ ########### Sessions
- # Article management
- map.resources :stock_takings,
- :collection => {:fill_new_stock_article_form => :get, :add_stock_article => :post}
- map.resources :stock_articles,
- :controller => 'stockit', :as => 'stockit',
- :collection => {:auto_complete_for_article_name => :get, :fill_new_stock_article_form => :get}
+ match '/login' => 'sessions#new', :as => 'login'
+ match '/logout' => 'sessions#destroy', :as => 'logout'
+ get '/login/forgot_password' => 'login#forgot_password', as: :forgot_password
+ get '/login/new_password' => 'login#new_password', as: :new_password
+ match '/login/accept_invitation/:token' => 'login#accept_invitation', as: :accept_invitation
+ resources :sessions, :only => [:new, :create, :destroy]
- map.resources :suppliers,
- :collection => { :shared_suppliers => :get } do |suppliers|
- suppliers.resources :deliveries,
- :member => { :drop_stock_change => :post },
- :collection => {:add_stock_article => :post}
- suppliers.resources :articles,
- :collection => { :update_selected => :post, :edit_all => :get, :update_all => :post,
- :upload => :get, :parse_upload => :post, :create_from_upload => :post,
- :shared => :get, :import => :get, :sync => :post }
- end
- map.resources :article_categories
+ ########### User specific
- # Finance
- map.namespace :finance do |finance|
- finance.root :controller => 'balancing'
- finance.balancing "balancing/list", :controller => 'balancing', :action => 'list'
- finance.resources :invoices
- finance.resources :transactions, :collection => {:new_collection => :get, :create_collection => :post}
- end
+ match '/home/profile' => 'home#profile', :as => 'my_profile'
+ match '/home/ordergroup' => 'home#ordergroup', :as => 'my_ordergroup'
+ match '/home/cancel_membership' => 'home#cancel_membership', :as => 'cancel_membership'
- # Administration
- map.namespace :admin do |admin|
- admin.root :controller => "base", :action => "index"
- admin.resources :users
- admin.resources :workgroups, :member => { :memberships => :get }
- admin.resources :ordergroups, :member => { :memberships => :get }
- end
+ ############ Wiki
- # Install the default route as the lowest priority.
- map.connect ':controller/:action/:id'
- map.connect ':controller/:action/:id.:format'
+ resources :pages do
+ get :all, :on => :collection
+ get :version, :on => :member
+ get :revert, :on => :member
+ end
+ match '/wiki/:permalink' => 'pages#show', :as => 'wiki_page' # , :constraints => {:permalink => /[^\s]+/}
+ match '/wiki' => 'pages#show', :defaults => {:permalink => 'Home'}, :as => 'wiki'
+
+ ############ Orders, ordering
+
+ resources :orders do
+ member do
+ post :finish
+ post :add_comment
+ end
+ end
+
+ resources :group_orders do
+ get :archive, :on => :collection
+ end
+
+ resources :order_comments, :only => [:new, :create]
+
+ ############ Foodcoop orga
+
+ resources :invites, :only => [:new, :create]
+
+ resources :tasks do
+ collection do
+ get :user
+ get :archive
+ get :workgroup
+ end
+ member do
+ post :accept
+ post :reject
+ post :set_done
+ end
+ end
+
+ resources :messages, :only => [:index, :show, :new, :create]
+
+ namespace :foodcoop do
+ root :to => 'users#index'
+
+ resources :users, :only => [:index]
+
+ resources :ordergroups, :only => [:index]
+
+ resources :workgroups, :only => [:index, :edit, :update]
+ end
+
+ ########### Article management
+
+ resources :stock_takings do
+ collection do
+ get :fill_new_stock_article_form
+ post :add_stock_article
+ end
+ end
+
+ resources :stock_articles, :to => 'stockit' do
+ collection do
+ get :articles_search
+ get :fill_new_stock_article_form
+ end
+ end
+
+ resources :suppliers do
+ get :shared_suppliers, :on => :collection
+
+ resources :deliveries do
+ post :drop_stock_change, :on => :member
+ post :add_stock_article, :on => :collection
+ end
+
+ resources :articles do
+ collection do
+ post :update_selected
+ get :edit_all
+ post :update_all
+ get :upload
+ post :parse_upload
+ post :create_from_upload
+ get :shared
+ get :import
+ post :sync
+ post :update_synchronized
+ end
+ end
+ end
+
+ resources :article_categories
+
+ ########### Finance
+
+ namespace :finance do
+ root :to => 'base#index'
+
+ resources :order, controller: 'balancing', path: 'balancing' do
+ member do
+ get :update_summary
+ get :edit_note
+ put :update_note
+
+ get :confirm
+ put :close
+ put :close_direct
+ end
+
+ resources :order_articles
+ end
+
+ resources :group_order_articles do
+ member do
+ put :update_result
+ end
+ end
+
+ resources :invoices
+
+ resources :ordergroups, :only => [:index] do
+ resources :financial_transactions, :as => :transactions
+ end
+
+ get 'transactions/new_collection' => 'financial_transactions#new_collection', :as => 'new_transaction_collection'
+ post 'transactions/create_collection' => 'financial_transactions#create_collection', :as => 'create_transaction_collection'
+ end
+
+ ########### Administration
+
+ namespace :admin do
+ root :to => 'base#index'
+
+ resources :users
+
+ resources :workgroups do
+ get :memberships, :on => :member
+ end
+
+ resources :ordergroups do
+ get :memberships, :on => :member
+ end
+ end
+
+ ############## Feedback
+
+ resource :feedback, :only => [:new, :create], :controller => 'feedback'
+
+ ############## The rest
+
+ resources :users, :only => [:index]
+
+ # TODO: This is very error prone. Better deactivate this catch all route
+ match ':controller(/:action(/:id))(.:format)'
+
+ end # End of /:foodcoop scope
end
diff --git a/config/schedule.rb b/config/schedule.rb
new file mode 100644
index 00000000..631e3d28
--- /dev/null
+++ b/config/schedule.rb
@@ -0,0 +1,15 @@
+# Use this file to define all tasks, which should be executed by cron
+# Learn more: http://github.com/javan/whenever
+
+# Upcoming tasks notifier
+every :day, :at => '7:20 am' do
+ rake "multicoops:run foodsoft:notify_upcoming_tasks"
+end
+
+# Weekly taks
+every :sunday, :at => '7:14 am' do
+ rake "multicoops:run foodsoft:create_upcoming_weekly_tasks"
+ rake "multicoops:run foodsoft:notify_users_of_weekly_task"
+end
+
+
diff --git a/db/migrate/20120929155541_add_ignore_apple_restriction_to_groups.rb b/db/migrate/20120929155541_add_ignore_apple_restriction_to_groups.rb
new file mode 100644
index 00000000..e3f71980
--- /dev/null
+++ b/db/migrate/20120929155541_add_ignore_apple_restriction_to_groups.rb
@@ -0,0 +1,9 @@
+class AddIgnoreAppleRestrictionToGroups < ActiveRecord::Migration
+ def self.up
+ add_column :groups, :ignore_apple_restriction, :boolean, default: false
+ end
+
+ def self.down
+ remove_column :groups, :ignore_apple_restriction
+ end
+end
diff --git a/db/migrate/20121216180646_remove_assigned_from_tasks.rb b/db/migrate/20121216180646_remove_assigned_from_tasks.rb
new file mode 100644
index 00000000..97fc6477
--- /dev/null
+++ b/db/migrate/20121216180646_remove_assigned_from_tasks.rb
@@ -0,0 +1,9 @@
+class RemoveAssignedFromTasks < ActiveRecord::Migration
+ def up
+ remove_column :tasks, :assigned
+ end
+
+ def down
+ add_column :tasks, :assigned, :boolean
+ end
+end
diff --git a/db/migrate/20121230142516_remove_account_updated_from_ordergroups.rb b/db/migrate/20121230142516_remove_account_updated_from_ordergroups.rb
new file mode 100644
index 00000000..0aedf521
--- /dev/null
+++ b/db/migrate/20121230142516_remove_account_updated_from_ordergroups.rb
@@ -0,0 +1,9 @@
+class RemoveAccountUpdatedFromOrdergroups < ActiveRecord::Migration
+ def up
+ remove_column :groups, :account_updated
+ end
+
+ def down
+ add_column :groups, :account_updated, :datetime
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 033e1ef6..188ea83b 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -1,15 +1,17 @@
-# This file is auto-generated from the current state of the database. Instead of editing this file,
-# please use the migrations feature of Active Record to incrementally modify your database, and
-# then regenerate this schema definition.
+# encoding: UTF-8
+# This file is auto-generated from the current state of the database. Instead
+# of editing this file, please use the migrations feature of Active Record to
+# incrementally modify your database, and then regenerate this schema definition.
#
-# Note that this schema.rb definition is the authoritative source for your database schema. If you need
-# to create the application database on another system, you should be using db:schema:load, not running
-# all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
+# Note that this schema.rb definition is the authoritative source for your
+# database schema. If you need to create the application database on another
+# system, you should be using db:schema:load, not running all the migrations
+# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 20121112093327) do
+ActiveRecord::Schema.define(:version => 20121230142516) do
create_table "article_categories", :force => true do |t|
t.string "name", :default => "", :null => false
@@ -135,7 +137,6 @@ ActiveRecord::Schema.define(:version => 20121112093327) do
t.string "name", :default => "", :null => false
t.string "description"
t.decimal "account_balance", :precision => 8, :scale => 2, :default => 0.0, :null => false
- t.datetime "account_updated"
t.datetime "created_on", :null => false
t.boolean "role_admin", :default => false, :null => false
t.boolean "role_suppliers", :default => false, :null => false
@@ -154,6 +155,7 @@ ActiveRecord::Schema.define(:version => 20121112093327) do
t.text "stats"
t.integer "task_duration", :default => 1
t.integer "next_weekly_tasks_number", :default => 8
+ t.boolean "ignore_apple_restriction", :default => false
end
add_index "groups", ["name"], :name => "index_groups_on_name", :unique => true
@@ -311,7 +313,6 @@ ActiveRecord::Schema.define(:version => 20121112093327) do
t.date "due_date"
t.boolean "done", :default => false
t.integer "workgroup_id"
- t.boolean "assigned", :default => false
t.datetime "created_on", :null => false
t.datetime "updated_on", :null => false
t.integer "required_users", :default => 1
diff --git a/doc/README_FOR_APP b/doc/README_FOR_APP
index a0186c07..79fdd74b 100644
--- a/doc/README_FOR_APP
+++ b/doc/README_FOR_APP
@@ -1,5 +1,5 @@
Use this README file to introduce your application and point to useful places in the API for learning more.
-Run "rake appdoc" to generate API documentation for your models and controllers.
+Run "rake doc:app" to generate API documentation for your models and controllers.
= The Foodsoft
diff --git a/lib/apple_bar.rb b/lib/apple_bar.rb
new file mode 100644
index 00000000..8249a296
--- /dev/null
+++ b/lib/apple_bar.rb
@@ -0,0 +1,44 @@
+class AppleBar
+
+ attr_reader :ordergroup
+
+ def initialize(ordergroup)
+ @ordergroup = ordergroup
+ @group_avg = ordergroup.avg_jobs_per_euro.to_f
+ @global_avg = Ordergroup.avg_jobs_per_euro
+ end
+
+ # Show group bar in following colors:
+ # Green if higher than 100
+ # Yellow if lower than 100 an higher than stop_ordering_under option value
+ # Red if below stop_ordering_under, the ordergroup isn't allowed to participate in an order anymore
+ def group_bar_state
+ if apples >= 100
+ 'success'
+ else
+ if FoodsoftConfig[:stop_ordering_under].present? and
+ apples >= FoodsoftConfig[:stop_ordering_under]
+ 'warning'
+ else
+ 'danger'
+ end
+ end
+ end
+
+ # Use apples as percentage, but show at least 10 percent
+ def group_bar_width
+ @ordergroup.apples < 2 ? 2 : @ordergroup.apples
+ end
+
+ def mean_order_amount_per_job
+ (1/@global_avg).round rescue 0
+ end
+
+ def apples
+ @apples ||= @ordergroup.apples
+ end
+
+ def with_restriction?
+ FoodsoftConfig[:stop_ordering_under].present?
+ end
+end
\ No newline at end of file
diff --git a/lib/foodcoop_filter.rb b/lib/foodcoop_filter.rb
deleted file mode 100644
index 10f81ec2..00000000
--- a/lib/foodcoop_filter.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-require 'routing_filter/base'
-
-module RoutingFilter
- class Foodcoop < Base
- def around_recognize(path, env, &block)
- token = extract_token!(path) # remove the token from the beginning of the path
- yield.tap do |params| # invoke the given block (calls more filters and finally routing)
- params[:foodcoop] = token if token # set recognized token to the resulting params hash
- end
- end
-
- def around_generate(*args, &block)
- token = args.extract_options!.delete(:foodcoop) # extract the passed :token option
- token = Foodsoft.env if token.nil? # default to Foodsoft.env
-
- yield.tap do |result|
- if token
- url = result.is_a?(Array) ? result.first : result
- prepend_token!(url, token)
- end
- end
- end
-
- protected
-
- def extract_token!(path)
- foodcoop = nil
- path.sub! %r(^/([a-zA-Z0-9]*)(?=/|$)) do foodcoop = $1; '' end
- foodcoop
- end
-
- def prepend_token!(url, token)
- url.sub!(%r(^(http.?://[^/]*)?(.*))) { "#{$1}/#{token}#{$2}" }
- end
-
- end
-end
\ No newline at end of file
diff --git a/lib/foodsoft_config.rb b/lib/foodsoft_config.rb
new file mode 100644
index 00000000..71b64024
--- /dev/null
+++ b/lib/foodsoft_config.rb
@@ -0,0 +1,50 @@
+class FoodsoftConfig
+ mattr_accessor :scope, :config
+ APP_CONFIG = YAML.load(File.read(File.join(Rails.root, "/config/app_config.yml")))
+
+ class << self
+
+ def init
+ # Load initial config from development or production
+ set_config Rails.env
+ # Overwrite scope to have a better namescope than 'production'
+ self.scope = config[:default_scope] or raise "No default_scope is set"
+ end
+
+ # Set config and database connection for specific foodcoop
+ # Only needed in multi coop mode
+ def select_foodcoop(foodcoop)
+ set_config foodcoop
+ setup_database
+ end
+
+ # Provides a nice accessor for config values
+ # FoodsoftConfig[:name] # => 'FC Test'
+ def [](key)
+ config[key]
+ end
+
+ # Loop through each foodcoop and executes the given block after setup config and database
+ def each_coop
+ APP_CONFIG.keys.reject { |coop| coop =~ /^(default|development|test|production)$/ }.each do |coop|
+ select_foodcoop coop
+ yield coop
+ end
+ end
+
+ private
+
+ def set_config(foodcoop)
+ raise "No config for this environment (#{foodcoop}) available!" if APP_CONFIG[foodcoop].nil?
+ self.config = APP_CONFIG[foodcoop].symbolize_keys
+ self.scope = foodcoop
+ end
+
+ def setup_database
+ database_config = ActiveRecord::Base.configurations[Rails.env]
+ database_config.merge!(config[:database]) if config[:database].present?
+ ActiveRecord::Base.establish_connection(database_config)
+ end
+
+ end
+end
\ No newline at end of file
diff --git a/lib/foodsoft_file.rb b/lib/foodsoft_file.rb
index 594c0ed9..1aa40dfb 100644
--- a/lib/foodsoft_file.rb
+++ b/lib/foodsoft_file.rb
@@ -1,7 +1,7 @@
# Module for FoodSoft-File import
# The FoodSoft-File is a cvs-file, with semicolon-seperatet columns
-
-require 'faster_csv'
+
+require 'csv'
module FoodsoftFile
@@ -11,7 +11,7 @@ module FoodsoftFile
def self.parse(file)
articles, outlisted_articles = Array.new, Array.new
row_index = 2
- FasterCSV.parse(file.read, {:col_sep => ";", :headers => true}) do |row|
+ ::CSV.parse(file.read, {:col_sep => ";", :headers => true}) do |row|
# check if the line is empty
unless row[2] == "" || row[2].nil?
article = {:number => row[1],
diff --git a/lib/order_pdf.rb b/lib/order_pdf.rb
new file mode 100644
index 00000000..f58e51a2
--- /dev/null
+++ b/lib/order_pdf.rb
@@ -0,0 +1,32 @@
+require "prawn/measurement_extensions"
+
+class OrderPdf < Prawn::Document
+ include ActionView::Helpers::NumberHelper
+
+ def initialize(order, options = {})
+ options[:page_size] ||= "A4"
+ #options[:left_margin] ||= 40
+ #options[:right_margin] ||= 40
+ options[:top_margin] ||= 50
+ #options[:bottom_margin] ||= 40
+ super(options)
+ @order = order
+ end
+
+ def to_pdf
+ # Define header
+ repeat :all, dynamic: true do
+ draw_text title, size: 10, style: :bold, at: [bounds.left, bounds.top+20] if title # Header
+ draw_text I18n.t('lib.order_pdf.page', :number => page_number), size: 8, at: [bounds.left, bounds.bottom-10] # Footer
+ end
+
+ body # Add content, which is defined in subclasses
+
+ render # Render pdf
+ end
+
+ # Helper method to test pdf via rails console: OrderByGroups.new(order).save_tmp
+ def save_tmp
+ File.open("#{Rails.root}/tmp/#{self.class.to_s.underscore}.pdf", 'w') {|f| f.write(to_pdf.force_encoding("UTF-8")) }
+ end
+end
diff --git a/vendor/plugins/acts_as_tree/test/database.yml b/lib/tasks/.gitkeep
similarity index 100%
rename from vendor/plugins/acts_as_tree/test/database.yml
rename to lib/tasks/.gitkeep
diff --git a/lib/tasks/foodsoft.rake b/lib/tasks/foodsoft.rake
index 446f2ace..0c8f0755 100644
--- a/lib/tasks/foodsoft.rake
+++ b/lib/tasks/foodsoft.rake
@@ -4,17 +4,14 @@
namespace :foodsoft do
desc "Notify users of upcoming tasks"
task :notify_upcoming_tasks => :environment do
- tasks = Task.find :all, :conditions => ["done = ? AND due_date = ?", false, 1.day.from_now.to_date]
+ tasks = Task.where(done: false, due_date: 1.day.from_now.to_date)
for task in tasks
puts "Send notifications for #{task.name} to .."
for user in task.users
- if user.settings['notify.upcoming_tasks'] == 1
- begin
- puts "#{user.email}.."
- Mailer.deliver_upcoming_tasks(user, task)
- rescue
- puts "deliver aborted for #{user.email}.."
- end
+ begin
+ Mailer.upcoming_tasks(user, task).deliver if user.settings['notify.upcoming_tasks'] == 1
+ rescue
+ puts "deliver aborted for #{user.email}.."
end
end
end
@@ -22,7 +19,7 @@ namespace :foodsoft do
desc "Create upcoming workgroups tasks (next 3 to 7 weeks)"
task :create_upcoming_weekly_tasks => :environment do
- workgroups = Workgroup.all :conditions => {:weekly_task => true}
+ workgroups = Workgroup.where(weekly_task: true)
for workgroup in workgroups
puts "Create weekly tasks for #{workgroup.name}"
# Loop through next tasks weekly tasks method,
@@ -38,13 +35,13 @@ namespace :foodsoft do
desc "Notify workgroup of upcoming weekly task"
task :notify_users_of_weekly_task => :environment do
for workgroup in Workgroup.all
- for task in workgroup.tasks.all(:conditions => ["due_date = ?", 7.days.from_now.to_date])
+ for task in workgroup.tasks.where(due_date: 7.days.from_now.to_date)
unless task.enough_users_assigned?
puts "Notify workgroup: #{workgroup.name} for task #{task.name}"
for user in workgroup.users
if user.settings['messages.sendAsEmail'] == "1" && !user.email.blank?
begin
- Mailer.deliver_not_enough_users_assigned(task, user)
+ Mailer.not_enough_users_assigned(task, user).deliver
rescue
puts "deliver aborted for #{user.email}"
end
@@ -54,36 +51,4 @@ namespace :foodsoft do
end
end
end
-
- desc "finished order tasks, cleanup, notifications, stats ..."
- task :finished_order_tasks => :environment do
- puts "Start: #{Time.now}"
- order = Order.find(ENV["ORDER_ID"])
-
- # Update GroupOrder prices
- order.group_orders.each { |go| go.update_price! }
-
- # Clean up
- # Delete no longer required order-history (group_order_article_quantities) and
- # TODO: Do we need articles, which aren't ordered? (units_to_order == 0 ?)
- order.order_articles.each do |oa|
- oa.group_order_articles.each { |goa| goa.group_order_article_quantities.clear }
- end
-
- # Notifications
- for group_order in order.group_orders
- for user in group_order.ordergroup.users
- begin
- Mailer.deliver_order_result(user, group_order) if user.settings["notify.orderFinished"] == '1'
- rescue
- puts "deliver aborted for #{user.email}.."
- end
- end
- end
-
- # Stats
- order.ordergroups.each { |o| o.update_stats! }
-
- puts "End: #{Time.now}"
- end
end
diff --git a/lib/tasks/messages.rake b/lib/tasks/messages.rake
deleted file mode 100644
index 160a1d80..00000000
--- a/lib/tasks/messages.rake
+++ /dev/null
@@ -1,4 +0,0 @@
-desc "Deliver messages as emails"
-task :send_emails => :environment do
- Message.send_emails
-end
diff --git a/lib/tasks/multicoops.rake b/lib/tasks/multicoops.rake
new file mode 100644
index 00000000..ccd16f6f
--- /dev/null
+++ b/lib/tasks/multicoops.rake
@@ -0,0 +1,20 @@
+namespace :multicoops do
+
+ desc 'Runs a specific rake task for each registered foodcoop, use rake multicoops:run db:migrate'
+ task :run => :environment do
+ task_to_run = ARGV[1]
+ FoodsoftConfig.each_coop do |coop|
+ puts "Run '#{task_to_run}' for #{coop}"
+ Rake::Task[task_to_run].execute
+ end
+ end
+
+ desc 'Runs a specific rake task for a single coop, use rake mutlicoops:run_single db:migrate FOODCOOP=demo'
+ task :run_single => :environment do
+ task_to_run = ARGV[1]
+ FoodsoftConfig.select_foodcoop ENV['FOODCOOP']
+ puts "Run '#{task_to_run}' for #{ENV['FOODCOOP']}"
+ Rake::Task[task_to_run].execute
+ end
+
+end
diff --git a/lib/tasks/resque.rake b/lib/tasks/resque.rake
new file mode 100644
index 00000000..40c2b93c
--- /dev/null
+++ b/lib/tasks/resque.rake
@@ -0,0 +1,41 @@
+require "resque/tasks"
+
+def run_worker(queue, count = 1)
+ puts "Starting #{count} worker(s) with QUEUE: #{queue}"
+ ops = {:pgroup => true, :err => ["log/resque_worker_foodsoft_notifier.log", "a"],
+ :out => ["log/resque_worker_foodsoft_notifier.log", "a"]}
+ env_vars = {"QUEUE" => queue.to_s, "PIDFILE" => "tmp/pids/resque_worker_foodsoft_notifier.pid", "VERBOSE" => "1"}
+ count.times {
+ ## Using Kernel.spawn and Process.detach because regular system() call would
+ ## cause the processes to quit when capistrano finishes
+ pid = spawn(env_vars, "bundle exec rake resque:work", ops)
+ Process.detach(pid)
+ }
+end
+
+namespace :resque do
+ task :setup => :environment
+
+ desc "Restart running workers"
+ task :restart_workers do
+ Rake::Task['resque:stop_workers'].invoke
+ Rake::Task['resque:start_workers'].invoke
+ end
+
+ desc "Quit running workers"
+ task :stop_workers do
+ pids = File.read('tmp/pids/resque_worker_foodsoft_notifier.pid').split("\n")
+ if pids.empty?
+ puts "No workers to kill"
+ else
+ syscmd = "kill -s QUIT #{pids.join(' ')}"
+ puts "Running syscmd: #{syscmd}"
+ system(syscmd)
+ end
+ end
+
+ desc "Start workers"
+ task :start_workers do
+ run_worker("foodsoft_notifier")
+ end
+end
diff --git a/lib/templates/haml/scaffold/_form.html.haml b/lib/templates/haml/scaffold/_form.html.haml
new file mode 100644
index 00000000..ac3aa7bc
--- /dev/null
+++ b/lib/templates/haml/scaffold/_form.html.haml
@@ -0,0 +1,10 @@
+= simple_form_for(@<%= singular_table_name %>) do |f|
+ = f.error_notification
+
+ .form-inputs
+ <%- attributes.each do |attribute| -%>
+ = f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %>
+ <%- end -%>
+
+ .form-actions
+ = f.button :submit
diff --git a/lib/wikilink.rb b/lib/wikilink.rb
index 6512c3fb..dc8c6b21 100644
--- a/lib/wikilink.rb
+++ b/lib/wikilink.rb
@@ -1,21 +1,22 @@
class Wikilink < WikiCloth::WikiLinkHandler
- include ActionController::UrlWriter # To use named routes
def link_attributes_for(page)
permalink = Page.permalink(page)
- url_options = {:host => Foodsoft.config[:host], :protocol => Foodsoft.config[:protocol]}
- url_options.merge!({:port => Foodsoft.config[:port]}) if Foodsoft.config[:port]
+ url_options = {:host => FoodsoftConfig[:host], :protocol => FoodsoftConfig[:protocol]}
+ url_options.merge!({:port => FoodsoftConfig[:port]}) if FoodsoftConfig[:port]
if Page.exists?(:permalink => permalink)
- { :href => url_for(url_options.merge({:controller => "pages", :action => "show",
- :permalink => permalink, :use_route => :wiki_page})) }
+ { :href => url_for(:wiki_page_path, permalink: permalink, use_route: :wiki_page) }
else
- { :href => url_for(url_options.merge({:controller => "pages", :action => "new",
- :title => page, :parent => params[:referer]})), :class => "new_wiki_link"}
+ { href: url_for(:new_page_path, title: page, parent: params[:referer]), class: 'new_wiki_link' }
end
end
def section_link(section)
""
end
+
+ def url_for(path_name, options = {})
+ Rails.application.routes.url_helpers.send path_name, options.merge({foodcoop: FoodsoftConfig.scope})
+ end
end
diff --git a/public/422.html b/public/422.html
new file mode 100644
index 00000000..83660ab1
--- /dev/null
+++ b/public/422.html
@@ -0,0 +1,26 @@
+
+
+
+ The change you wanted was rejected (422)
+
+
+
+
+
+
+
The change you wanted was rejected.
+
Maybe you tried to change something you didn't have access to.
+
+
+
diff --git a/public/images/arrow_down_red.png b/public/images/arrow_down_red.png
deleted file mode 100644
index abfe29a1..00000000
Binary files a/public/images/arrow_down_red.png and /dev/null differ
diff --git a/public/images/arrow_right_red.png b/public/images/arrow_right_red.png
deleted file mode 100644
index bf351f6d..00000000
Binary files a/public/images/arrow_right_red.png and /dev/null differ
diff --git a/public/images/arrow_up_red.png b/public/images/arrow_up_red.png
deleted file mode 100644
index ba5db380..00000000
Binary files a/public/images/arrow_up_red.png and /dev/null differ
diff --git a/public/images/rails.png b/public/images/rails.png
deleted file mode 100644
index b8441f18..00000000
Binary files a/public/images/rails.png and /dev/null differ
diff --git a/public/javascripts/application.js b/public/javascripts/application.js
deleted file mode 100644
index 185fecf3..00000000
--- a/public/javascripts/application.js
+++ /dev/null
@@ -1,54 +0,0 @@
-// Place your application-specific JavaScript functions and classes here
-// This file is automatically included by javascript_include_tag :defaults
-
-// for checkboxes. just insert box in same form-element like:
-//
-// credit to Shawn Olson & http://www.shawnolson.net
-function checkUncheckAll(theElement) {
- var theForm = theElement.form, z = 0;
- for(z=0; z" + elementName + ">";
- } catch(e) {}
- var element = parentElement.firstChild || null;
-
- // see if browser added wrapping tags
- if(element && (element.tagName.toUpperCase() != elementName))
- element = element.getElementsByTagName(elementName)[0];
-
- // fallback to createElement approach
- if(!element) element = document.createElement(elementName);
-
- // abort if nothing could be created
- if(!element) return;
-
- // attributes (or text)
- if(arguments[1])
- if(this._isStringOrNumber(arguments[1]) ||
- (arguments[1] instanceof Array) ||
- arguments[1].tagName) {
- this._children(element, arguments[1]);
- } else {
- var attrs = this._attributes(arguments[1]);
- if(attrs.length) {
- try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
- parentElement.innerHTML = "<" +elementName + " " +
- attrs + ">" + elementName + ">";
- } catch(e) {}
- element = parentElement.firstChild || null;
- // workaround firefox 1.0.X bug
- if(!element) {
- element = document.createElement(elementName);
- for(attr in arguments[1])
- element[attr == 'class' ? 'className' : attr] = arguments[1][attr];
- }
- if(element.tagName.toUpperCase() != elementName)
- element = parentElement.getElementsByTagName(elementName)[0];
- }
- }
-
- // text, or array of children
- if(arguments[2])
- this._children(element, arguments[2]);
-
- return element;
- },
- _text: function(text) {
- return document.createTextNode(text);
- },
-
- ATTR_MAP: {
- 'className': 'class',
- 'htmlFor': 'for'
- },
-
- _attributes: function(attributes) {
- var attrs = [];
- for(attribute in attributes)
- attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) +
- '="' + attributes[attribute].toString().escapeHTML().gsub(/"/,'"') + '"');
- return attrs.join(" ");
- },
- _children: function(element, children) {
- if(children.tagName) {
- element.appendChild(children);
- return;
- }
- if(typeof children=='object') { // array can hold nodes and text
- children.flatten().each( function(e) {
- if(typeof e=='object')
- element.appendChild(e)
- else
- if(Builder._isStringOrNumber(e))
- element.appendChild(Builder._text(e));
- });
- } else
- if(Builder._isStringOrNumber(children))
- element.appendChild(Builder._text(children));
- },
- _isStringOrNumber: function(param) {
- return(typeof param=='string' || typeof param=='number');
- },
- build: function(html) {
- var element = this.node('div');
- $(element).update(html.strip());
- return element.down();
- },
- dump: function(scope) {
- if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope
-
- var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " +
- "BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " +
- "FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+
- "KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+
- "PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+
- "TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/);
-
- tags.each( function(tag){
- scope[tag] = function() {
- return Builder.node.apply(Builder, [tag].concat($A(arguments)));
- }
- });
- }
-}
diff --git a/public/javascripts/controls.js b/public/javascripts/controls.js
deleted file mode 100644
index ca29aefd..00000000
--- a/public/javascripts/controls.js
+++ /dev/null
@@ -1,963 +0,0 @@
-// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
-// (c) 2005-2008 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
-// (c) 2005-2008 Jon Tirsen (http://www.tirsen.com)
-// Contributors:
-// Richard Livsey
-// Rahul Bhargava
-// Rob Wills
-//
-// script.aculo.us is freely distributable under the terms of an MIT-style license.
-// For details, see the script.aculo.us web site: http://script.aculo.us/
-
-// Autocompleter.Base handles all the autocompletion functionality
-// that's independent of the data source for autocompletion. This
-// includes drawing the autocompletion menu, observing keyboard
-// and mouse events, and similar.
-//
-// Specific autocompleters need to provide, at the very least,
-// a getUpdatedChoices function that will be invoked every time
-// the text inside the monitored textbox changes. This method
-// should get the text for which to provide autocompletion by
-// invoking this.getToken(), NOT by directly accessing
-// this.element.value. This is to allow incremental tokenized
-// autocompletion. Specific auto-completion logic (AJAX, etc)
-// belongs in getUpdatedChoices.
-//
-// Tokenized incremental autocompletion is enabled automatically
-// when an autocompleter is instantiated with the 'tokens' option
-// in the options parameter, e.g.:
-// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
-// will incrementally autocomplete with a comma as the token.
-// Additionally, ',' in the above example can be replaced with
-// a token array, e.g. { tokens: [',', '\n'] } which
-// enables autocompletion on multiple tokens. This is most
-// useful when one of the tokens is \n (a newline), as it
-// allows smart autocompletion after linebreaks.
-
-if(typeof Effect == 'undefined')
- throw("controls.js requires including script.aculo.us' effects.js library");
-
-var Autocompleter = { };
-Autocompleter.Base = Class.create({
- baseInitialize: function(element, update, options) {
- element = $(element);
- this.element = element;
- this.update = $(update);
- this.hasFocus = false;
- this.changed = false;
- this.active = false;
- this.index = 0;
- this.entryCount = 0;
- this.oldElementValue = this.element.value;
-
- if(this.setOptions)
- this.setOptions(options);
- else
- this.options = options || { };
-
- this.options.paramName = this.options.paramName || this.element.name;
- this.options.tokens = this.options.tokens || [];
- this.options.frequency = this.options.frequency || 0.4;
- this.options.minChars = this.options.minChars || 1;
- this.options.onShow = this.options.onShow ||
- function(element, update){
- if(!update.style.position || update.style.position=='absolute') {
- update.style.position = 'absolute';
- Position.clone(element, update, {
- setHeight: false,
- offsetTop: element.offsetHeight
- });
- }
- Effect.Appear(update,{duration:0.15});
- };
- this.options.onHide = this.options.onHide ||
- function(element, update){ new Effect.Fade(update,{duration:0.15}) };
-
- if(typeof(this.options.tokens) == 'string')
- this.options.tokens = new Array(this.options.tokens);
- // Force carriage returns as token delimiters anyway
- if (!this.options.tokens.include('\n'))
- this.options.tokens.push('\n');
-
- this.observer = null;
-
- this.element.setAttribute('autocomplete','off');
-
- Element.hide(this.update);
-
- Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this));
- Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this));
- },
-
- show: function() {
- if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
- if(!this.iefix &&
- (Prototype.Browser.IE) &&
- (Element.getStyle(this.update, 'position')=='absolute')) {
- new Insertion.After(this.update,
- '');
- this.iefix = $(this.update.id+'_iefix');
- }
- if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
- },
-
- fixIEOverlapping: function() {
- Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
- this.iefix.style.zIndex = 1;
- this.update.style.zIndex = 2;
- Element.show(this.iefix);
- },
-
- hide: function() {
- this.stopIndicator();
- if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);
- if(this.iefix) Element.hide(this.iefix);
- },
-
- startIndicator: function() {
- if(this.options.indicator) Element.show(this.options.indicator);
- },
-
- stopIndicator: function() {
- if(this.options.indicator) Element.hide(this.options.indicator);
- },
-
- onKeyPress: function(event) {
- if(this.active)
- switch(event.keyCode) {
- case Event.KEY_TAB:
- case Event.KEY_RETURN:
- this.selectEntry();
- Event.stop(event);
- case Event.KEY_ESC:
- this.hide();
- this.active = false;
- Event.stop(event);
- return;
- case Event.KEY_LEFT:
- case Event.KEY_RIGHT:
- return;
- case Event.KEY_UP:
- this.markPrevious();
- this.render();
- Event.stop(event);
- return;
- case Event.KEY_DOWN:
- this.markNext();
- this.render();
- Event.stop(event);
- return;
- }
- else
- if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||
- (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return;
-
- this.changed = true;
- this.hasFocus = true;
-
- if(this.observer) clearTimeout(this.observer);
- this.observer =
- setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
- },
-
- activate: function() {
- this.changed = false;
- this.hasFocus = true;
- this.getUpdatedChoices();
- },
-
- onHover: function(event) {
- var element = Event.findElement(event, 'LI');
- if(this.index != element.autocompleteIndex)
- {
- this.index = element.autocompleteIndex;
- this.render();
- }
- Event.stop(event);
- },
-
- onClick: function(event) {
- var element = Event.findElement(event, 'LI');
- this.index = element.autocompleteIndex;
- this.selectEntry();
- this.hide();
- },
-
- onBlur: function(event) {
- // needed to make click events working
- setTimeout(this.hide.bind(this), 250);
- this.hasFocus = false;
- this.active = false;
- },
-
- render: function() {
- if(this.entryCount > 0) {
- for (var i = 0; i < this.entryCount; i++)
- this.index==i ?
- Element.addClassName(this.getEntry(i),"selected") :
- Element.removeClassName(this.getEntry(i),"selected");
- if(this.hasFocus) {
- this.show();
- this.active = true;
- }
- } else {
- this.active = false;
- this.hide();
- }
- },
-
- markPrevious: function() {
- if(this.index > 0) this.index--;
- else this.index = this.entryCount-1;
- this.getEntry(this.index).scrollIntoView(true);
- },
-
- markNext: function() {
- if(this.index < this.entryCount-1) this.index++;
- else this.index = 0;
- this.getEntry(this.index).scrollIntoView(false);
- },
-
- getEntry: function(index) {
- return this.update.firstChild.childNodes[index];
- },
-
- getCurrentEntry: function() {
- return this.getEntry(this.index);
- },
-
- selectEntry: function() {
- this.active = false;
- this.updateElement(this.getCurrentEntry());
- },
-
- updateElement: function(selectedElement) {
- if (this.options.updateElement) {
- this.options.updateElement(selectedElement);
- return;
- }
- var value = '';
- if (this.options.select) {
- var nodes = $(selectedElement).select('.' + this.options.select) || [];
- if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
- } else
- value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
-
- var bounds = this.getTokenBounds();
- if (bounds[0] != -1) {
- var newValue = this.element.value.substr(0, bounds[0]);
- var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/);
- if (whitespace)
- newValue += whitespace[0];
- this.element.value = newValue + value + this.element.value.substr(bounds[1]);
- } else {
- this.element.value = value;
- }
- this.oldElementValue = this.element.value;
- this.element.focus();
-
- if (this.options.afterUpdateElement)
- this.options.afterUpdateElement(this.element, selectedElement);
- },
-
- updateChoices: function(choices) {
- if(!this.changed && this.hasFocus) {
- this.update.innerHTML = choices;
- Element.cleanWhitespace(this.update);
- Element.cleanWhitespace(this.update.down());
-
- if(this.update.firstChild && this.update.down().childNodes) {
- this.entryCount =
- this.update.down().childNodes.length;
- for (var i = 0; i < this.entryCount; i++) {
- var entry = this.getEntry(i);
- entry.autocompleteIndex = i;
- this.addObservers(entry);
- }
- } else {
- this.entryCount = 0;
- }
-
- this.stopIndicator();
- this.index = 0;
-
- if(this.entryCount==1 && this.options.autoSelect) {
- this.selectEntry();
- this.hide();
- } else {
- this.render();
- }
- }
- },
-
- addObservers: function(element) {
- Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
- Event.observe(element, "click", this.onClick.bindAsEventListener(this));
- },
-
- onObserverEvent: function() {
- this.changed = false;
- this.tokenBounds = null;
- if(this.getToken().length>=this.options.minChars) {
- this.getUpdatedChoices();
- } else {
- this.active = false;
- this.hide();
- }
- this.oldElementValue = this.element.value;
- },
-
- getToken: function() {
- var bounds = this.getTokenBounds();
- return this.element.value.substring(bounds[0], bounds[1]).strip();
- },
-
- getTokenBounds: function() {
- if (null != this.tokenBounds) return this.tokenBounds;
- var value = this.element.value;
- if (value.strip().empty()) return [-1, 0];
- var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue);
- var offset = (diff == this.oldElementValue.length ? 1 : 0);
- var prevTokenPos = -1, nextTokenPos = value.length;
- var tp;
- for (var index = 0, l = this.options.tokens.length; index < l; ++index) {
- tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1);
- if (tp > prevTokenPos) prevTokenPos = tp;
- tp = value.indexOf(this.options.tokens[index], diff + offset);
- if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp;
- }
- return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]);
- }
-});
-
-Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) {
- var boundary = Math.min(newS.length, oldS.length);
- for (var index = 0; index < boundary; ++index)
- if (newS[index] != oldS[index])
- return index;
- return boundary;
-};
-
-Ajax.Autocompleter = Class.create(Autocompleter.Base, {
- initialize: function(element, update, url, options) {
- this.baseInitialize(element, update, options);
- this.options.asynchronous = true;
- this.options.onComplete = this.onComplete.bind(this);
- this.options.defaultParams = this.options.parameters || null;
- this.url = url;
- },
-
- getUpdatedChoices: function() {
- this.startIndicator();
-
- var entry = encodeURIComponent(this.options.paramName) + '=' +
- encodeURIComponent(this.getToken());
-
- this.options.parameters = this.options.callback ?
- this.options.callback(this.element, entry) : entry;
-
- if(this.options.defaultParams)
- this.options.parameters += '&' + this.options.defaultParams;
-
- new Ajax.Request(this.url, this.options);
- },
-
- onComplete: function(request) {
- this.updateChoices(request.responseText);
- }
-});
-
-// The local array autocompleter. Used when you'd prefer to
-// inject an array of autocompletion options into the page, rather
-// than sending out Ajax queries, which can be quite slow sometimes.
-//
-// The constructor takes four parameters. The first two are, as usual,
-// the id of the monitored textbox, and id of the autocompletion menu.
-// The third is the array you want to autocomplete from, and the fourth
-// is the options block.
-//
-// Extra local autocompletion options:
-// - choices - How many autocompletion choices to offer
-//
-// - partialSearch - If false, the autocompleter will match entered
-// text only at the beginning of strings in the
-// autocomplete array. Defaults to true, which will
-// match text at the beginning of any *word* in the
-// strings in the autocomplete array. If you want to
-// search anywhere in the string, additionally set
-// the option fullSearch to true (default: off).
-//
-// - fullSsearch - Search anywhere in autocomplete array strings.
-//
-// - partialChars - How many characters to enter before triggering
-// a partial match (unlike minChars, which defines
-// how many characters are required to do any match
-// at all). Defaults to 2.
-//
-// - ignoreCase - Whether to ignore case when autocompleting.
-// Defaults to true.
-//
-// It's possible to pass in a custom function as the 'selector'
-// option, if you prefer to write your own autocompletion logic.
-// In that case, the other options above will not apply unless
-// you support them.
-
-Autocompleter.Local = Class.create(Autocompleter.Base, {
- initialize: function(element, update, array, options) {
- this.baseInitialize(element, update, options);
- this.options.array = array;
- },
-
- getUpdatedChoices: function() {
- this.updateChoices(this.options.selector(this));
- },
-
- setOptions: function(options) {
- this.options = Object.extend({
- choices: 10,
- partialSearch: true,
- partialChars: 2,
- ignoreCase: true,
- fullSearch: false,
- selector: function(instance) {
- var ret = []; // Beginning matches
- var partial = []; // Inside matches
- var entry = instance.getToken();
- var count = 0;
-
- for (var i = 0; i < instance.options.array.length &&
- ret.length < instance.options.choices ; i++) {
-
- var elem = instance.options.array[i];
- var foundPos = instance.options.ignoreCase ?
- elem.toLowerCase().indexOf(entry.toLowerCase()) :
- elem.indexOf(entry);
-
- while (foundPos != -1) {
- if (foundPos == 0 && elem.length != entry.length) {
- ret.push("" + elem.substr(0, entry.length) + " " +
- elem.substr(entry.length) + " ");
- break;
- } else if (entry.length >= instance.options.partialChars &&
- instance.options.partialSearch && foundPos != -1) {
- if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {
- partial.push("" + elem.substr(0, foundPos) + "" +
- elem.substr(foundPos, entry.length) + " " + elem.substr(
- foundPos + entry.length) + " ");
- break;
- }
- }
-
- foundPos = instance.options.ignoreCase ?
- elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :
- elem.indexOf(entry, foundPos + 1);
-
- }
- }
- if (partial.length)
- ret = ret.concat(partial.slice(0, instance.options.choices - ret.length));
- return "";
- }
- }, options || { });
- }
-});
-
-// AJAX in-place editor and collection editor
-// Full rewrite by Christophe Porteneuve (April 2007).
-
-// Use this if you notice weird scrolling problems on some browsers,
-// the DOM might be a bit confused when this gets called so do this
-// waits 1 ms (with setTimeout) until it does the activation
-Field.scrollFreeActivate = function(field) {
- setTimeout(function() {
- Field.activate(field);
- }, 1);
-};
-
-Ajax.InPlaceEditor = Class.create({
- initialize: function(element, url, options) {
- this.url = url;
- this.element = element = $(element);
- this.prepareOptions();
- this._controls = { };
- arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!!
- Object.extend(this.options, options || { });
- if (!this.options.formId && this.element.id) {
- this.options.formId = this.element.id + '-inplaceeditor';
- if ($(this.options.formId))
- this.options.formId = '';
- }
- if (this.options.externalControl)
- this.options.externalControl = $(this.options.externalControl);
- if (!this.options.externalControl)
- this.options.externalControlOnly = false;
- this._originalBackground = this.element.getStyle('background-color') || 'transparent';
- this.element.title = this.options.clickToEditText;
- this._boundCancelHandler = this.handleFormCancellation.bind(this);
- this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this);
- this._boundFailureHandler = this.handleAJAXFailure.bind(this);
- this._boundSubmitHandler = this.handleFormSubmission.bind(this);
- this._boundWrapperHandler = this.wrapUp.bind(this);
- this.registerListeners();
- },
- checkForEscapeOrReturn: function(e) {
- if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return;
- if (Event.KEY_ESC == e.keyCode)
- this.handleFormCancellation(e);
- else if (Event.KEY_RETURN == e.keyCode)
- this.handleFormSubmission(e);
- },
- createControl: function(mode, handler, extraClasses) {
- var control = this.options[mode + 'Control'];
- var text = this.options[mode + 'Text'];
- if ('button' == control) {
- var btn = document.createElement('input');
- btn.type = 'submit';
- btn.value = text;
- btn.className = 'editor_' + mode + '_button';
- if ('cancel' == mode)
- btn.onclick = this._boundCancelHandler;
- this._form.appendChild(btn);
- this._controls[mode] = btn;
- } else if ('link' == control) {
- var link = document.createElement('a');
- link.href = '#';
- link.appendChild(document.createTextNode(text));
- link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler;
- link.className = 'editor_' + mode + '_link';
- if (extraClasses)
- link.className += ' ' + extraClasses;
- this._form.appendChild(link);
- this._controls[mode] = link;
- }
- },
- createEditField: function() {
- var text = (this.options.loadTextURL ? this.options.loadingText : this.getText());
- var fld;
- if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) {
- fld = document.createElement('input');
- fld.type = 'text';
- var size = this.options.size || this.options.cols || 0;
- if (0 < size) fld.size = size;
- } else {
- fld = document.createElement('textarea');
- fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows);
- fld.cols = this.options.cols || 40;
- }
- fld.name = this.options.paramName;
- fld.value = text; // No HTML breaks conversion anymore
- fld.className = 'editor_field';
- if (this.options.submitOnBlur)
- fld.onblur = this._boundSubmitHandler;
- this._controls.editor = fld;
- if (this.options.loadTextURL)
- this.loadExternalText();
- this._form.appendChild(this._controls.editor);
- },
- createForm: function() {
- var ipe = this;
- function addText(mode, condition) {
- var text = ipe.options['text' + mode + 'Controls'];
- if (!text || condition === false) return;
- ipe._form.appendChild(document.createTextNode(text));
- };
- this._form = $(document.createElement('form'));
- this._form.id = this.options.formId;
- this._form.addClassName(this.options.formClassName);
- this._form.onsubmit = this._boundSubmitHandler;
- this.createEditField();
- if ('textarea' == this._controls.editor.tagName.toLowerCase())
- this._form.appendChild(document.createElement('br'));
- if (this.options.onFormCustomization)
- this.options.onFormCustomization(this, this._form);
- addText('Before', this.options.okControl || this.options.cancelControl);
- this.createControl('ok', this._boundSubmitHandler);
- addText('Between', this.options.okControl && this.options.cancelControl);
- this.createControl('cancel', this._boundCancelHandler, 'editor_cancel');
- addText('After', this.options.okControl || this.options.cancelControl);
- },
- destroy: function() {
- if (this._oldInnerHTML)
- this.element.innerHTML = this._oldInnerHTML;
- this.leaveEditMode();
- this.unregisterListeners();
- },
- enterEditMode: function(e) {
- if (this._saving || this._editing) return;
- this._editing = true;
- this.triggerCallback('onEnterEditMode');
- if (this.options.externalControl)
- this.options.externalControl.hide();
- this.element.hide();
- this.createForm();
- this.element.parentNode.insertBefore(this._form, this.element);
- if (!this.options.loadTextURL)
- this.postProcessEditField();
- if (e) Event.stop(e);
- },
- enterHover: function(e) {
- if (this.options.hoverClassName)
- this.element.addClassName(this.options.hoverClassName);
- if (this._saving) return;
- this.triggerCallback('onEnterHover');
- },
- getText: function() {
- return this.element.innerHTML.unescapeHTML();
- },
- handleAJAXFailure: function(transport) {
- this.triggerCallback('onFailure', transport);
- if (this._oldInnerHTML) {
- this.element.innerHTML = this._oldInnerHTML;
- this._oldInnerHTML = null;
- }
- },
- handleFormCancellation: function(e) {
- this.wrapUp();
- if (e) Event.stop(e);
- },
- handleFormSubmission: function(e) {
- var form = this._form;
- var value = $F(this._controls.editor);
- this.prepareSubmission();
- var params = this.options.callback(form, value) || '';
- if (Object.isString(params))
- params = params.toQueryParams();
- params.editorId = this.element.id;
- if (this.options.htmlResponse) {
- var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions);
- Object.extend(options, {
- parameters: params,
- onComplete: this._boundWrapperHandler,
- onFailure: this._boundFailureHandler
- });
- new Ajax.Updater({ success: this.element }, this.url, options);
- } else {
- var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
- Object.extend(options, {
- parameters: params,
- onComplete: this._boundWrapperHandler,
- onFailure: this._boundFailureHandler
- });
- new Ajax.Request(this.url, options);
- }
- if (e) Event.stop(e);
- },
- leaveEditMode: function() {
- this.element.removeClassName(this.options.savingClassName);
- this.removeForm();
- this.leaveHover();
- this.element.style.backgroundColor = this._originalBackground;
- this.element.show();
- if (this.options.externalControl)
- this.options.externalControl.show();
- this._saving = false;
- this._editing = false;
- this._oldInnerHTML = null;
- this.triggerCallback('onLeaveEditMode');
- },
- leaveHover: function(e) {
- if (this.options.hoverClassName)
- this.element.removeClassName(this.options.hoverClassName);
- if (this._saving) return;
- this.triggerCallback('onLeaveHover');
- },
- loadExternalText: function() {
- this._form.addClassName(this.options.loadingClassName);
- this._controls.editor.disabled = true;
- var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
- Object.extend(options, {
- parameters: 'editorId=' + encodeURIComponent(this.element.id),
- onComplete: Prototype.emptyFunction,
- onSuccess: function(transport) {
- this._form.removeClassName(this.options.loadingClassName);
- var text = transport.responseText;
- if (this.options.stripLoadedTextTags)
- text = text.stripTags();
- this._controls.editor.value = text;
- this._controls.editor.disabled = false;
- this.postProcessEditField();
- }.bind(this),
- onFailure: this._boundFailureHandler
- });
- new Ajax.Request(this.options.loadTextURL, options);
- },
- postProcessEditField: function() {
- var fpc = this.options.fieldPostCreation;
- if (fpc)
- $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate']();
- },
- prepareOptions: function() {
- this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions);
- Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks);
- [this._extraDefaultOptions].flatten().compact().each(function(defs) {
- Object.extend(this.options, defs);
- }.bind(this));
- },
- prepareSubmission: function() {
- this._saving = true;
- this.removeForm();
- this.leaveHover();
- this.showSaving();
- },
- registerListeners: function() {
- this._listeners = { };
- var listener;
- $H(Ajax.InPlaceEditor.Listeners).each(function(pair) {
- listener = this[pair.value].bind(this);
- this._listeners[pair.key] = listener;
- if (!this.options.externalControlOnly)
- this.element.observe(pair.key, listener);
- if (this.options.externalControl)
- this.options.externalControl.observe(pair.key, listener);
- }.bind(this));
- },
- removeForm: function() {
- if (!this._form) return;
- this._form.remove();
- this._form = null;
- this._controls = { };
- },
- showSaving: function() {
- this._oldInnerHTML = this.element.innerHTML;
- this.element.innerHTML = this.options.savingText;
- this.element.addClassName(this.options.savingClassName);
- this.element.style.backgroundColor = this._originalBackground;
- this.element.show();
- },
- triggerCallback: function(cbName, arg) {
- if ('function' == typeof this.options[cbName]) {
- this.options[cbName](this, arg);
- }
- },
- unregisterListeners: function() {
- $H(this._listeners).each(function(pair) {
- if (!this.options.externalControlOnly)
- this.element.stopObserving(pair.key, pair.value);
- if (this.options.externalControl)
- this.options.externalControl.stopObserving(pair.key, pair.value);
- }.bind(this));
- },
- wrapUp: function(transport) {
- this.leaveEditMode();
- // Can't use triggerCallback due to backward compatibility: requires
- // binding + direct element
- this._boundComplete(transport, this.element);
- }
-});
-
-Object.extend(Ajax.InPlaceEditor.prototype, {
- dispose: Ajax.InPlaceEditor.prototype.destroy
-});
-
-Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, {
- initialize: function($super, element, url, options) {
- this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions;
- $super(element, url, options);
- },
-
- createEditField: function() {
- var list = document.createElement('select');
- list.name = this.options.paramName;
- list.size = 1;
- this._controls.editor = list;
- this._collection = this.options.collection || [];
- if (this.options.loadCollectionURL)
- this.loadCollection();
- else
- this.checkForExternalText();
- this._form.appendChild(this._controls.editor);
- },
-
- loadCollection: function() {
- this._form.addClassName(this.options.loadingClassName);
- this.showLoadingText(this.options.loadingCollectionText);
- var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
- Object.extend(options, {
- parameters: 'editorId=' + encodeURIComponent(this.element.id),
- onComplete: Prototype.emptyFunction,
- onSuccess: function(transport) {
- var js = transport.responseText.strip();
- if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check
- throw('Server returned an invalid collection representation.');
- this._collection = eval(js);
- this.checkForExternalText();
- }.bind(this),
- onFailure: this.onFailure
- });
- new Ajax.Request(this.options.loadCollectionURL, options);
- },
-
- showLoadingText: function(text) {
- this._controls.editor.disabled = true;
- var tempOption = this._controls.editor.firstChild;
- if (!tempOption) {
- tempOption = document.createElement('option');
- tempOption.value = '';
- this._controls.editor.appendChild(tempOption);
- tempOption.selected = true;
- }
- tempOption.update((text || '').stripScripts().stripTags());
- },
-
- checkForExternalText: function() {
- this._text = this.getText();
- if (this.options.loadTextURL)
- this.loadExternalText();
- else
- this.buildOptionList();
- },
-
- loadExternalText: function() {
- this.showLoadingText(this.options.loadingText);
- var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
- Object.extend(options, {
- parameters: 'editorId=' + encodeURIComponent(this.element.id),
- onComplete: Prototype.emptyFunction,
- onSuccess: function(transport) {
- this._text = transport.responseText.strip();
- this.buildOptionList();
- }.bind(this),
- onFailure: this.onFailure
- });
- new Ajax.Request(this.options.loadTextURL, options);
- },
-
- buildOptionList: function() {
- this._form.removeClassName(this.options.loadingClassName);
- this._collection = this._collection.map(function(entry) {
- return 2 === entry.length ? entry : [entry, entry].flatten();
- });
- var marker = ('value' in this.options) ? this.options.value : this._text;
- var textFound = this._collection.any(function(entry) {
- return entry[0] == marker;
- }.bind(this));
- this._controls.editor.update('');
- var option;
- this._collection.each(function(entry, index) {
- option = document.createElement('option');
- option.value = entry[0];
- option.selected = textFound ? entry[0] == marker : 0 == index;
- option.appendChild(document.createTextNode(entry[1]));
- this._controls.editor.appendChild(option);
- }.bind(this));
- this._controls.editor.disabled = false;
- Field.scrollFreeActivate(this._controls.editor);
- }
-});
-
-//**** DEPRECATION LAYER FOR InPlace[Collection]Editor! ****
-//**** This only exists for a while, in order to let ****
-//**** users adapt to the new API. Read up on the new ****
-//**** API and convert your code to it ASAP! ****
-
-Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) {
- if (!options) return;
- function fallback(name, expr) {
- if (name in options || expr === undefined) return;
- options[name] = expr;
- };
- fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' :
- options.cancelLink == options.cancelButton == false ? false : undefined)));
- fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' :
- options.okLink == options.okButton == false ? false : undefined)));
- fallback('highlightColor', options.highlightcolor);
- fallback('highlightEndColor', options.highlightendcolor);
-};
-
-Object.extend(Ajax.InPlaceEditor, {
- DefaultOptions: {
- ajaxOptions: { },
- autoRows: 3, // Use when multi-line w/ rows == 1
- cancelControl: 'link', // 'link'|'button'|false
- cancelText: 'cancel',
- clickToEditText: 'Click to edit',
- externalControl: null, // id|elt
- externalControlOnly: false,
- fieldPostCreation: 'activate', // 'activate'|'focus'|false
- formClassName: 'inplaceeditor-form',
- formId: null, // id|elt
- highlightColor: '#ffff99',
- highlightEndColor: '#ffffff',
- hoverClassName: '',
- htmlResponse: true,
- loadingClassName: 'inplaceeditor-loading',
- loadingText: 'Loading...',
- okControl: 'button', // 'link'|'button'|false
- okText: 'ok',
- paramName: 'value',
- rows: 1, // If 1 and multi-line, uses autoRows
- savingClassName: 'inplaceeditor-saving',
- savingText: 'Saving...',
- size: 0,
- stripLoadedTextTags: false,
- submitOnBlur: false,
- textAfterControls: '',
- textBeforeControls: '',
- textBetweenControls: ''
- },
- DefaultCallbacks: {
- callback: function(form) {
- return Form.serialize(form);
- },
- onComplete: function(transport, element) {
- // For backward compatibility, this one is bound to the IPE, and passes
- // the element directly. It was too often customized, so we don't break it.
- new Effect.Highlight(element, {
- startcolor: this.options.highlightColor, keepBackgroundImage: true });
- },
- onEnterEditMode: null,
- onEnterHover: function(ipe) {
- ipe.element.style.backgroundColor = ipe.options.highlightColor;
- if (ipe._effect)
- ipe._effect.cancel();
- },
- onFailure: function(transport, ipe) {
- alert('Error communication with the server: ' + transport.responseText.stripTags());
- },
- onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls.
- onLeaveEditMode: null,
- onLeaveHover: function(ipe) {
- ipe._effect = new Effect.Highlight(ipe.element, {
- startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor,
- restorecolor: ipe._originalBackground, keepBackgroundImage: true
- });
- }
- },
- Listeners: {
- click: 'enterEditMode',
- keydown: 'checkForEscapeOrReturn',
- mouseover: 'enterHover',
- mouseout: 'leaveHover'
- }
-});
-
-Ajax.InPlaceCollectionEditor.DefaultOptions = {
- loadingCollectionText: 'Loading options...'
-};
-
-// Delayed observer, like Form.Element.Observer,
-// but waits for delay after last key input
-// Ideal for live-search fields
-
-Form.Element.DelayedObserver = Class.create({
- initialize: function(element, delay, callback) {
- this.delay = delay || 0.5;
- this.element = $(element);
- this.callback = callback;
- this.timer = null;
- this.lastValue = $F(this.element);
- Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
- },
- delayedListener: function(event) {
- if(this.lastValue == $F(this.element)) return;
- if(this.timer) clearTimeout(this.timer);
- this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);
- this.lastValue = $F(this.element);
- },
- onTimerEvent: function() {
- this.timer = null;
- this.callback(this.element, $F(this.element));
- }
-});
\ No newline at end of file
diff --git a/public/javascripts/dragdrop.js b/public/javascripts/dragdrop.js
deleted file mode 100644
index 07229f98..00000000
--- a/public/javascripts/dragdrop.js
+++ /dev/null
@@ -1,973 +0,0 @@
-// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
-// (c) 2005-2008 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
-//
-// script.aculo.us is freely distributable under the terms of an MIT-style license.
-// For details, see the script.aculo.us web site: http://script.aculo.us/
-
-if(Object.isUndefined(Effect))
- throw("dragdrop.js requires including script.aculo.us' effects.js library");
-
-var Droppables = {
- drops: [],
-
- remove: function(element) {
- this.drops = this.drops.reject(function(d) { return d.element==$(element) });
- },
-
- add: function(element) {
- element = $(element);
- var options = Object.extend({
- greedy: true,
- hoverclass: null,
- tree: false
- }, arguments[1] || { });
-
- // cache containers
- if(options.containment) {
- options._containers = [];
- var containment = options.containment;
- if(Object.isArray(containment)) {
- containment.each( function(c) { options._containers.push($(c)) });
- } else {
- options._containers.push($(containment));
- }
- }
-
- if(options.accept) options.accept = [options.accept].flatten();
-
- Element.makePositioned(element); // fix IE
- options.element = element;
-
- this.drops.push(options);
- },
-
- findDeepestChild: function(drops) {
- deepest = drops[0];
-
- for (i = 1; i < drops.length; ++i)
- if (Element.isParent(drops[i].element, deepest.element))
- deepest = drops[i];
-
- return deepest;
- },
-
- isContained: function(element, drop) {
- var containmentNode;
- if(drop.tree) {
- containmentNode = element.treeNode;
- } else {
- containmentNode = element.parentNode;
- }
- return drop._containers.detect(function(c) { return containmentNode == c });
- },
-
- isAffected: function(point, element, drop) {
- return (
- (drop.element!=element) &&
- ((!drop._containers) ||
- this.isContained(element, drop)) &&
- ((!drop.accept) ||
- (Element.classNames(element).detect(
- function(v) { return drop.accept.include(v) } ) )) &&
- Position.within(drop.element, point[0], point[1]) );
- },
-
- deactivate: function(drop) {
- if(drop.hoverclass)
- Element.removeClassName(drop.element, drop.hoverclass);
- this.last_active = null;
- },
-
- activate: function(drop) {
- if(drop.hoverclass)
- Element.addClassName(drop.element, drop.hoverclass);
- this.last_active = drop;
- },
-
- show: function(point, element) {
- if(!this.drops.length) return;
- var drop, affected = [];
-
- this.drops.each( function(drop) {
- if(Droppables.isAffected(point, element, drop))
- affected.push(drop);
- });
-
- if(affected.length>0)
- drop = Droppables.findDeepestChild(affected);
-
- if(this.last_active && this.last_active != drop) this.deactivate(this.last_active);
- if (drop) {
- Position.within(drop.element, point[0], point[1]);
- if(drop.onHover)
- drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
-
- if (drop != this.last_active) Droppables.activate(drop);
- }
- },
-
- fire: function(event, element) {
- if(!this.last_active) return;
- Position.prepare();
-
- if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
- if (this.last_active.onDrop) {
- this.last_active.onDrop(element, this.last_active.element, event);
- return true;
- }
- },
-
- reset: function() {
- if(this.last_active)
- this.deactivate(this.last_active);
- }
-};
-
-var Draggables = {
- drags: [],
- observers: [],
-
- register: function(draggable) {
- if(this.drags.length == 0) {
- this.eventMouseUp = this.endDrag.bindAsEventListener(this);
- this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
- this.eventKeypress = this.keyPress.bindAsEventListener(this);
-
- Event.observe(document, "mouseup", this.eventMouseUp);
- Event.observe(document, "mousemove", this.eventMouseMove);
- Event.observe(document, "keypress", this.eventKeypress);
- }
- this.drags.push(draggable);
- },
-
- unregister: function(draggable) {
- this.drags = this.drags.reject(function(d) { return d==draggable });
- if(this.drags.length == 0) {
- Event.stopObserving(document, "mouseup", this.eventMouseUp);
- Event.stopObserving(document, "mousemove", this.eventMouseMove);
- Event.stopObserving(document, "keypress", this.eventKeypress);
- }
- },
-
- activate: function(draggable) {
- if(draggable.options.delay) {
- this._timeout = setTimeout(function() {
- Draggables._timeout = null;
- window.focus();
- Draggables.activeDraggable = draggable;
- }.bind(this), draggable.options.delay);
- } else {
- window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
- this.activeDraggable = draggable;
- }
- },
-
- deactivate: function() {
- this.activeDraggable = null;
- },
-
- updateDrag: function(event) {
- if(!this.activeDraggable) return;
- var pointer = [Event.pointerX(event), Event.pointerY(event)];
- // Mozilla-based browsers fire successive mousemove events with
- // the same coordinates, prevent needless redrawing (moz bug?)
- if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
- this._lastPointer = pointer;
-
- this.activeDraggable.updateDrag(event, pointer);
- },
-
- endDrag: function(event) {
- if(this._timeout) {
- clearTimeout(this._timeout);
- this._timeout = null;
- }
- if(!this.activeDraggable) return;
- this._lastPointer = null;
- this.activeDraggable.endDrag(event);
- this.activeDraggable = null;
- },
-
- keyPress: function(event) {
- if(this.activeDraggable)
- this.activeDraggable.keyPress(event);
- },
-
- addObserver: function(observer) {
- this.observers.push(observer);
- this._cacheObserverCallbacks();
- },
-
- removeObserver: function(element) { // element instead of observer fixes mem leaks
- this.observers = this.observers.reject( function(o) { return o.element==element });
- this._cacheObserverCallbacks();
- },
-
- notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag'
- if(this[eventName+'Count'] > 0)
- this.observers.each( function(o) {
- if(o[eventName]) o[eventName](eventName, draggable, event);
- });
- if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
- },
-
- _cacheObserverCallbacks: function() {
- ['onStart','onEnd','onDrag'].each( function(eventName) {
- Draggables[eventName+'Count'] = Draggables.observers.select(
- function(o) { return o[eventName]; }
- ).length;
- });
- }
-};
-
-/*--------------------------------------------------------------------------*/
-
-var Draggable = Class.create({
- initialize: function(element) {
- var defaults = {
- handle: false,
- reverteffect: function(element, top_offset, left_offset) {
- var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
- new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur,
- queue: {scope:'_draggable', position:'end'}
- });
- },
- endeffect: function(element) {
- var toOpacity = Object.isNumber(element._opacity) ? element._opacity : 1.0;
- new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,
- queue: {scope:'_draggable', position:'end'},
- afterFinish: function(){
- Draggable._dragging[element] = false
- }
- });
- },
- zindex: 1000,
- revert: false,
- quiet: false,
- scroll: false,
- scrollSensitivity: 20,
- scrollSpeed: 15,
- snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] }
- delay: 0
- };
-
- if(!arguments[1] || Object.isUndefined(arguments[1].endeffect))
- Object.extend(defaults, {
- starteffect: function(element) {
- element._opacity = Element.getOpacity(element);
- Draggable._dragging[element] = true;
- new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});
- }
- });
-
- var options = Object.extend(defaults, arguments[1] || { });
-
- this.element = $(element);
-
- if(options.handle && Object.isString(options.handle))
- this.handle = this.element.down('.'+options.handle, 0);
-
- if(!this.handle) this.handle = $(options.handle);
- if(!this.handle) this.handle = this.element;
-
- if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
- options.scroll = $(options.scroll);
- this._isScrollChild = Element.childOf(this.element, options.scroll);
- }
-
- Element.makePositioned(this.element); // fix IE
-
- this.options = options;
- this.dragging = false;
-
- this.eventMouseDown = this.initDrag.bindAsEventListener(this);
- Event.observe(this.handle, "mousedown", this.eventMouseDown);
-
- Draggables.register(this);
- },
-
- destroy: function() {
- Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
- Draggables.unregister(this);
- },
-
- currentDelta: function() {
- return([
- parseInt(Element.getStyle(this.element,'left') || '0'),
- parseInt(Element.getStyle(this.element,'top') || '0')]);
- },
-
- initDrag: function(event) {
- if(!Object.isUndefined(Draggable._dragging[this.element]) &&
- Draggable._dragging[this.element]) return;
- if(Event.isLeftClick(event)) {
- // abort on form elements, fixes a Firefox issue
- var src = Event.element(event);
- if((tag_name = src.tagName.toUpperCase()) && (
- tag_name=='INPUT' ||
- tag_name=='SELECT' ||
- tag_name=='OPTION' ||
- tag_name=='BUTTON' ||
- tag_name=='TEXTAREA')) return;
-
- var pointer = [Event.pointerX(event), Event.pointerY(event)];
- var pos = Position.cumulativeOffset(this.element);
- this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
-
- Draggables.activate(this);
- Event.stop(event);
- }
- },
-
- startDrag: function(event) {
- this.dragging = true;
- if(!this.delta)
- this.delta = this.currentDelta();
-
- if(this.options.zindex) {
- this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
- this.element.style.zIndex = this.options.zindex;
- }
-
- if(this.options.ghosting) {
- this._clone = this.element.cloneNode(true);
- this._originallyAbsolute = (this.element.getStyle('position') == 'absolute');
- if (!this._originallyAbsolute)
- Position.absolutize(this.element);
- this.element.parentNode.insertBefore(this._clone, this.element);
- }
-
- if(this.options.scroll) {
- if (this.options.scroll == window) {
- var where = this._getWindowScroll(this.options.scroll);
- this.originalScrollLeft = where.left;
- this.originalScrollTop = where.top;
- } else {
- this.originalScrollLeft = this.options.scroll.scrollLeft;
- this.originalScrollTop = this.options.scroll.scrollTop;
- }
- }
-
- Draggables.notify('onStart', this, event);
-
- if(this.options.starteffect) this.options.starteffect(this.element);
- },
-
- updateDrag: function(event, pointer) {
- if(!this.dragging) this.startDrag(event);
-
- if(!this.options.quiet){
- Position.prepare();
- Droppables.show(pointer, this.element);
- }
-
- Draggables.notify('onDrag', this, event);
-
- this.draw(pointer);
- if(this.options.change) this.options.change(this);
-
- if(this.options.scroll) {
- this.stopScrolling();
-
- var p;
- if (this.options.scroll == window) {
- with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
- } else {
- p = Position.page(this.options.scroll);
- p[0] += this.options.scroll.scrollLeft + Position.deltaX;
- p[1] += this.options.scroll.scrollTop + Position.deltaY;
- p.push(p[0]+this.options.scroll.offsetWidth);
- p.push(p[1]+this.options.scroll.offsetHeight);
- }
- var speed = [0,0];
- if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);
- if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);
- if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);
- if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
- this.startScrolling(speed);
- }
-
- // fix AppleWebKit rendering
- if(Prototype.Browser.WebKit) window.scrollBy(0,0);
-
- Event.stop(event);
- },
-
- finishDrag: function(event, success) {
- this.dragging = false;
-
- if(this.options.quiet){
- Position.prepare();
- var pointer = [Event.pointerX(event), Event.pointerY(event)];
- Droppables.show(pointer, this.element);
- }
-
- if(this.options.ghosting) {
- if (!this._originallyAbsolute)
- Position.relativize(this.element);
- delete this._originallyAbsolute;
- Element.remove(this._clone);
- this._clone = null;
- }
-
- var dropped = false;
- if(success) {
- dropped = Droppables.fire(event, this.element);
- if (!dropped) dropped = false;
- }
- if(dropped && this.options.onDropped) this.options.onDropped(this.element);
- Draggables.notify('onEnd', this, event);
-
- var revert = this.options.revert;
- if(revert && Object.isFunction(revert)) revert = revert(this.element);
-
- var d = this.currentDelta();
- if(revert && this.options.reverteffect) {
- if (dropped == 0 || revert != 'failure')
- this.options.reverteffect(this.element,
- d[1]-this.delta[1], d[0]-this.delta[0]);
- } else {
- this.delta = d;
- }
-
- if(this.options.zindex)
- this.element.style.zIndex = this.originalZ;
-
- if(this.options.endeffect)
- this.options.endeffect(this.element);
-
- Draggables.deactivate(this);
- Droppables.reset();
- },
-
- keyPress: function(event) {
- if(event.keyCode!=Event.KEY_ESC) return;
- this.finishDrag(event, false);
- Event.stop(event);
- },
-
- endDrag: function(event) {
- if(!this.dragging) return;
- this.stopScrolling();
- this.finishDrag(event, true);
- Event.stop(event);
- },
-
- draw: function(point) {
- var pos = Position.cumulativeOffset(this.element);
- if(this.options.ghosting) {
- var r = Position.realOffset(this.element);
- pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
- }
-
- var d = this.currentDelta();
- pos[0] -= d[0]; pos[1] -= d[1];
-
- if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
- pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
- pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
- }
-
- var p = [0,1].map(function(i){
- return (point[i]-pos[i]-this.offset[i])
- }.bind(this));
-
- if(this.options.snap) {
- if(Object.isFunction(this.options.snap)) {
- p = this.options.snap(p[0],p[1],this);
- } else {
- if(Object.isArray(this.options.snap)) {
- p = p.map( function(v, i) {
- return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this));
- } else {
- p = p.map( function(v) {
- return (v/this.options.snap).round()*this.options.snap }.bind(this));
- }
- }}
-
- var style = this.element.style;
- if((!this.options.constraint) || (this.options.constraint=='horizontal'))
- style.left = p[0] + "px";
- if((!this.options.constraint) || (this.options.constraint=='vertical'))
- style.top = p[1] + "px";
-
- if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
- },
-
- stopScrolling: function() {
- if(this.scrollInterval) {
- clearInterval(this.scrollInterval);
- this.scrollInterval = null;
- Draggables._lastScrollPointer = null;
- }
- },
-
- startScrolling: function(speed) {
- if(!(speed[0] || speed[1])) return;
- this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
- this.lastScrolled = new Date();
- this.scrollInterval = setInterval(this.scroll.bind(this), 10);
- },
-
- scroll: function() {
- var current = new Date();
- var delta = current - this.lastScrolled;
- this.lastScrolled = current;
- if(this.options.scroll == window) {
- with (this._getWindowScroll(this.options.scroll)) {
- if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
- var d = delta / 1000;
- this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] );
- }
- }
- } else {
- this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
- this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000;
- }
-
- Position.prepare();
- Droppables.show(Draggables._lastPointer, this.element);
- Draggables.notify('onDrag', this);
- if (this._isScrollChild) {
- Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
- Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
- Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
- if (Draggables._lastScrollPointer[0] < 0)
- Draggables._lastScrollPointer[0] = 0;
- if (Draggables._lastScrollPointer[1] < 0)
- Draggables._lastScrollPointer[1] = 0;
- this.draw(Draggables._lastScrollPointer);
- }
-
- if(this.options.change) this.options.change(this);
- },
-
- _getWindowScroll: function(w) {
- var T, L, W, H;
- with (w.document) {
- if (w.document.documentElement && documentElement.scrollTop) {
- T = documentElement.scrollTop;
- L = documentElement.scrollLeft;
- } else if (w.document.body) {
- T = body.scrollTop;
- L = body.scrollLeft;
- }
- if (w.innerWidth) {
- W = w.innerWidth;
- H = w.innerHeight;
- } else if (w.document.documentElement && documentElement.clientWidth) {
- W = documentElement.clientWidth;
- H = documentElement.clientHeight;
- } else {
- W = body.offsetWidth;
- H = body.offsetHeight;
- }
- }
- return { top: T, left: L, width: W, height: H };
- }
-});
-
-Draggable._dragging = { };
-
-/*--------------------------------------------------------------------------*/
-
-var SortableObserver = Class.create({
- initialize: function(element, observer) {
- this.element = $(element);
- this.observer = observer;
- this.lastValue = Sortable.serialize(this.element);
- },
-
- onStart: function() {
- this.lastValue = Sortable.serialize(this.element);
- },
-
- onEnd: function() {
- Sortable.unmark();
- if(this.lastValue != Sortable.serialize(this.element))
- this.observer(this.element)
- }
-});
-
-var Sortable = {
- SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
-
- sortables: { },
-
- _findRootElement: function(element) {
- while (element.tagName.toUpperCase() != "BODY") {
- if(element.id && Sortable.sortables[element.id]) return element;
- element = element.parentNode;
- }
- },
-
- options: function(element) {
- element = Sortable._findRootElement($(element));
- if(!element) return;
- return Sortable.sortables[element.id];
- },
-
- destroy: function(element){
- element = $(element);
- var s = Sortable.sortables[element.id];
-
- if(s) {
- Draggables.removeObserver(s.element);
- s.droppables.each(function(d){ Droppables.remove(d) });
- s.draggables.invoke('destroy');
-
- delete Sortable.sortables[s.element.id];
- }
- },
-
- create: function(element) {
- element = $(element);
- var options = Object.extend({
- element: element,
- tag: 'li', // assumes li children, override with tag: 'tagname'
- dropOnEmpty: false,
- tree: false,
- treeTag: 'ul',
- overlap: 'vertical', // one of 'vertical', 'horizontal'
- constraint: 'vertical', // one of 'vertical', 'horizontal', false
- containment: element, // also takes array of elements (or id's); or false
- handle: false, // or a CSS class
- only: false,
- delay: 0,
- hoverclass: null,
- ghosting: false,
- quiet: false,
- scroll: false,
- scrollSensitivity: 20,
- scrollSpeed: 15,
- format: this.SERIALIZE_RULE,
-
- // these take arrays of elements or ids and can be
- // used for better initialization performance
- elements: false,
- handles: false,
-
- onChange: Prototype.emptyFunction,
- onUpdate: Prototype.emptyFunction
- }, arguments[1] || { });
-
- // clear any old sortable with same element
- this.destroy(element);
-
- // build options for the draggables
- var options_for_draggable = {
- revert: true,
- quiet: options.quiet,
- scroll: options.scroll,
- scrollSpeed: options.scrollSpeed,
- scrollSensitivity: options.scrollSensitivity,
- delay: options.delay,
- ghosting: options.ghosting,
- constraint: options.constraint,
- handle: options.handle };
-
- if(options.starteffect)
- options_for_draggable.starteffect = options.starteffect;
-
- if(options.reverteffect)
- options_for_draggable.reverteffect = options.reverteffect;
- else
- if(options.ghosting) options_for_draggable.reverteffect = function(element) {
- element.style.top = 0;
- element.style.left = 0;
- };
-
- if(options.endeffect)
- options_for_draggable.endeffect = options.endeffect;
-
- if(options.zindex)
- options_for_draggable.zindex = options.zindex;
-
- // build options for the droppables
- var options_for_droppable = {
- overlap: options.overlap,
- containment: options.containment,
- tree: options.tree,
- hoverclass: options.hoverclass,
- onHover: Sortable.onHover
- };
-
- var options_for_tree = {
- onHover: Sortable.onEmptyHover,
- overlap: options.overlap,
- containment: options.containment,
- hoverclass: options.hoverclass
- };
-
- // fix for gecko engine
- Element.cleanWhitespace(element);
-
- options.draggables = [];
- options.droppables = [];
-
- // drop on empty handling
- if(options.dropOnEmpty || options.tree) {
- Droppables.add(element, options_for_tree);
- options.droppables.push(element);
- }
-
- (options.elements || this.findElements(element, options) || []).each( function(e,i) {
- var handle = options.handles ? $(options.handles[i]) :
- (options.handle ? $(e).select('.' + options.handle)[0] : e);
- options.draggables.push(
- new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
- Droppables.add(e, options_for_droppable);
- if(options.tree) e.treeNode = element;
- options.droppables.push(e);
- });
-
- if(options.tree) {
- (Sortable.findTreeElements(element, options) || []).each( function(e) {
- Droppables.add(e, options_for_tree);
- e.treeNode = element;
- options.droppables.push(e);
- });
- }
-
- // keep reference
- this.sortables[element.id] = options;
-
- // for onupdate
- Draggables.addObserver(new SortableObserver(element, options.onUpdate));
-
- },
-
- // return all suitable-for-sortable elements in a guaranteed order
- findElements: function(element, options) {
- return Element.findChildren(
- element, options.only, options.tree ? true : false, options.tag);
- },
-
- findTreeElements: function(element, options) {
- return Element.findChildren(
- element, options.only, options.tree ? true : false, options.treeTag);
- },
-
- onHover: function(element, dropon, overlap) {
- if(Element.isParent(dropon, element)) return;
-
- if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) {
- return;
- } else if(overlap>0.5) {
- Sortable.mark(dropon, 'before');
- if(dropon.previousSibling != element) {
- var oldParentNode = element.parentNode;
- element.style.visibility = "hidden"; // fix gecko rendering
- dropon.parentNode.insertBefore(element, dropon);
- if(dropon.parentNode!=oldParentNode)
- Sortable.options(oldParentNode).onChange(element);
- Sortable.options(dropon.parentNode).onChange(element);
- }
- } else {
- Sortable.mark(dropon, 'after');
- var nextElement = dropon.nextSibling || null;
- if(nextElement != element) {
- var oldParentNode = element.parentNode;
- element.style.visibility = "hidden"; // fix gecko rendering
- dropon.parentNode.insertBefore(element, nextElement);
- if(dropon.parentNode!=oldParentNode)
- Sortable.options(oldParentNode).onChange(element);
- Sortable.options(dropon.parentNode).onChange(element);
- }
- }
- },
-
- onEmptyHover: function(element, dropon, overlap) {
- var oldParentNode = element.parentNode;
- var droponOptions = Sortable.options(dropon);
-
- if(!Element.isParent(dropon, element)) {
- var index;
-
- var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only});
- var child = null;
-
- if(children) {
- var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
-
- for (index = 0; index < children.length; index += 1) {
- if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {
- offset -= Element.offsetSize (children[index], droponOptions.overlap);
- } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
- child = index + 1 < children.length ? children[index + 1] : null;
- break;
- } else {
- child = children[index];
- break;
- }
- }
- }
-
- dropon.insertBefore(element, child);
-
- Sortable.options(oldParentNode).onChange(element);
- droponOptions.onChange(element);
- }
- },
-
- unmark: function() {
- if(Sortable._marker) Sortable._marker.hide();
- },
-
- mark: function(dropon, position) {
- // mark on ghosting only
- var sortable = Sortable.options(dropon.parentNode);
- if(sortable && !sortable.ghosting) return;
-
- if(!Sortable._marker) {
- Sortable._marker =
- ($('dropmarker') || Element.extend(document.createElement('DIV'))).
- hide().addClassName('dropmarker').setStyle({position:'absolute'});
- document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
- }
- var offsets = Position.cumulativeOffset(dropon);
- Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'});
-
- if(position=='after')
- if(sortable.overlap == 'horizontal')
- Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'});
- else
- Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'});
-
- Sortable._marker.show();
- },
-
- _tree: function(element, options, parent) {
- var children = Sortable.findElements(element, options) || [];
-
- for (var i = 0; i < children.length; ++i) {
- var match = children[i].id.match(options.format);
-
- if (!match) continue;
-
- var child = {
- id: encodeURIComponent(match ? match[1] : null),
- element: element,
- parent: parent,
- children: [],
- position: parent.children.length,
- container: $(children[i]).down(options.treeTag)
- };
-
- /* Get the element containing the children and recurse over it */
- if (child.container)
- this._tree(child.container, options, child);
-
- parent.children.push (child);
- }
-
- return parent;
- },
-
- tree: function(element) {
- element = $(element);
- var sortableOptions = this.options(element);
- var options = Object.extend({
- tag: sortableOptions.tag,
- treeTag: sortableOptions.treeTag,
- only: sortableOptions.only,
- name: element.id,
- format: sortableOptions.format
- }, arguments[1] || { });
-
- var root = {
- id: null,
- parent: null,
- children: [],
- container: element,
- position: 0
- };
-
- return Sortable._tree(element, options, root);
- },
-
- /* Construct a [i] index for a particular node */
- _constructIndex: function(node) {
- var index = '';
- do {
- if (node.id) index = '[' + node.position + ']' + index;
- } while ((node = node.parent) != null);
- return index;
- },
-
- sequence: function(element) {
- element = $(element);
- var options = Object.extend(this.options(element), arguments[1] || { });
-
- return $(this.findElements(element, options) || []).map( function(item) {
- return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
- });
- },
-
- setSequence: function(element, new_sequence) {
- element = $(element);
- var options = Object.extend(this.options(element), arguments[2] || { });
-
- var nodeMap = { };
- this.findElements(element, options).each( function(n) {
- if (n.id.match(options.format))
- nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
- n.parentNode.removeChild(n);
- });
-
- new_sequence.each(function(ident) {
- var n = nodeMap[ident];
- if (n) {
- n[1].appendChild(n[0]);
- delete nodeMap[ident];
- }
- });
- },
-
- serialize: function(element) {
- element = $(element);
- var options = Object.extend(Sortable.options(element), arguments[1] || { });
- var name = encodeURIComponent(
- (arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
-
- if (options.tree) {
- return Sortable.tree(element, arguments[1]).children.map( function (item) {
- return [name + Sortable._constructIndex(item) + "[id]=" +
- encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
- }).flatten().join('&');
- } else {
- return Sortable.sequence(element, arguments[1]).map( function(item) {
- return name + "[]=" + encodeURIComponent(item);
- }).join('&');
- }
- }
-};
-
-// Returns true if child is contained within element
-Element.isParent = function(child, element) {
- if (!child.parentNode || child == element) return false;
- if (child.parentNode == element) return true;
- return Element.isParent(child.parentNode, element);
-};
-
-Element.findChildren = function(element, only, recursive, tagName) {
- if(!element.hasChildNodes()) return null;
- tagName = tagName.toUpperCase();
- if(only) only = [only].flatten();
- var elements = [];
- $A(element.childNodes).each( function(e) {
- if(e.tagName && e.tagName.toUpperCase()==tagName &&
- (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
- elements.push(e);
- if(recursive) {
- var grandchildren = Element.findChildren(e, only, recursive, tagName);
- if(grandchildren) elements.push(grandchildren);
- }
- });
-
- return (elements.length>0 ? elements.flatten() : []);
-};
-
-Element.offsetSize = function (element, type) {
- return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')];
-};
\ No newline at end of file
diff --git a/public/javascripts/effects.js b/public/javascripts/effects.js
deleted file mode 100644
index 5a639d2d..00000000
--- a/public/javascripts/effects.js
+++ /dev/null
@@ -1,1128 +0,0 @@
-// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
-// Contributors:
-// Justin Palmer (http://encytemedia.com/)
-// Mark Pilgrim (http://diveintomark.org/)
-// Martin Bialasinki
-//
-// script.aculo.us is freely distributable under the terms of an MIT-style license.
-// For details, see the script.aculo.us web site: http://script.aculo.us/
-
-// converts rgb() and #xxx to #xxxxxx format,
-// returns self (or first argument) if not convertable
-String.prototype.parseColor = function() {
- var color = '#';
- if (this.slice(0,4) == 'rgb(') {
- var cols = this.slice(4,this.length-1).split(',');
- var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
- } else {
- if (this.slice(0,1) == '#') {
- if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
- if (this.length==7) color = this.toLowerCase();
- }
- }
- return (color.length==7 ? color : (arguments[0] || this));
-};
-
-/*--------------------------------------------------------------------------*/
-
-Element.collectTextNodes = function(element) {
- return $A($(element).childNodes).collect( function(node) {
- return (node.nodeType==3 ? node.nodeValue :
- (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
- }).flatten().join('');
-};
-
-Element.collectTextNodesIgnoreClass = function(element, className) {
- return $A($(element).childNodes).collect( function(node) {
- return (node.nodeType==3 ? node.nodeValue :
- ((node.hasChildNodes() && !Element.hasClassName(node,className)) ?
- Element.collectTextNodesIgnoreClass(node, className) : ''));
- }).flatten().join('');
-};
-
-Element.setContentZoom = function(element, percent) {
- element = $(element);
- element.setStyle({fontSize: (percent/100) + 'em'});
- if (Prototype.Browser.WebKit) window.scrollBy(0,0);
- return element;
-};
-
-Element.getInlineOpacity = function(element){
- return $(element).style.opacity || '';
-};
-
-Element.forceRerendering = function(element) {
- try {
- element = $(element);
- var n = document.createTextNode(' ');
- element.appendChild(n);
- element.removeChild(n);
- } catch(e) { }
-};
-
-/*--------------------------------------------------------------------------*/
-
-var Effect = {
- _elementDoesNotExistError: {
- name: 'ElementDoesNotExistError',
- message: 'The specified DOM element does not exist, but is required for this effect to operate'
- },
- Transitions: {
- linear: Prototype.K,
- sinoidal: function(pos) {
- return (-Math.cos(pos*Math.PI)/2) + .5;
- },
- reverse: function(pos) {
- return 1-pos;
- },
- flicker: function(pos) {
- var pos = ((-Math.cos(pos*Math.PI)/4) + .75) + Math.random()/4;
- return pos > 1 ? 1 : pos;
- },
- wobble: function(pos) {
- return (-Math.cos(pos*Math.PI*(9*pos))/2) + .5;
- },
- pulse: function(pos, pulses) {
- return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5;
- },
- spring: function(pos) {
- return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));
- },
- none: function(pos) {
- return 0;
- },
- full: function(pos) {
- return 1;
- }
- },
- DefaultOptions: {
- duration: 1.0, // seconds
- fps: 100, // 100= assume 66fps max.
- sync: false, // true for combining
- from: 0.0,
- to: 1.0,
- delay: 0.0,
- queue: 'parallel'
- },
- tagifyText: function(element) {
- var tagifyStyle = 'position:relative';
- if (Prototype.Browser.IE) tagifyStyle += ';zoom:1';
-
- element = $(element);
- $A(element.childNodes).each( function(child) {
- if (child.nodeType==3) {
- child.nodeValue.toArray().each( function(character) {
- element.insertBefore(
- new Element('span', {style: tagifyStyle}).update(
- character == ' ' ? String.fromCharCode(160) : character),
- child);
- });
- Element.remove(child);
- }
- });
- },
- multiple: function(element, effect) {
- var elements;
- if (((typeof element == 'object') ||
- Object.isFunction(element)) &&
- (element.length))
- elements = element;
- else
- elements = $(element).childNodes;
-
- var options = Object.extend({
- speed: 0.1,
- delay: 0.0
- }, arguments[2] || { });
- var masterDelay = options.delay;
-
- $A(elements).each( function(element, index) {
- new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
- });
- },
- PAIRS: {
- 'slide': ['SlideDown','SlideUp'],
- 'blind': ['BlindDown','BlindUp'],
- 'appear': ['Appear','Fade']
- },
- toggle: function(element, effect) {
- element = $(element);
- effect = (effect || 'appear').toLowerCase();
- var options = Object.extend({
- queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
- }, arguments[2] || { });
- Effect[element.visible() ?
- Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
- }
-};
-
-Effect.DefaultOptions.transition = Effect.Transitions.sinoidal;
-
-/* ------------- core effects ------------- */
-
-Effect.ScopedQueue = Class.create(Enumerable, {
- initialize: function() {
- this.effects = [];
- this.interval = null;
- },
- _each: function(iterator) {
- this.effects._each(iterator);
- },
- add: function(effect) {
- var timestamp = new Date().getTime();
-
- var position = Object.isString(effect.options.queue) ?
- effect.options.queue : effect.options.queue.position;
-
- switch(position) {
- case 'front':
- // move unstarted effects after this effect
- this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
- e.startOn += effect.finishOn;
- e.finishOn += effect.finishOn;
- });
- break;
- case 'with-last':
- timestamp = this.effects.pluck('startOn').max() || timestamp;
- break;
- case 'end':
- // start effect after last queued effect has finished
- timestamp = this.effects.pluck('finishOn').max() || timestamp;
- break;
- }
-
- effect.startOn += timestamp;
- effect.finishOn += timestamp;
-
- if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
- this.effects.push(effect);
-
- if (!this.interval)
- this.interval = setInterval(this.loop.bind(this), 15);
- },
- remove: function(effect) {
- this.effects = this.effects.reject(function(e) { return e==effect });
- if (this.effects.length == 0) {
- clearInterval(this.interval);
- this.interval = null;
- }
- },
- loop: function() {
- var timePos = new Date().getTime();
- for(var i=0, len=this.effects.length;i= this.startOn) {
- if (timePos >= this.finishOn) {
- this.render(1.0);
- this.cancel();
- this.event('beforeFinish');
- if (this.finish) this.finish();
- this.event('afterFinish');
- return;
- }
- var pos = (timePos - this.startOn) / this.totalTime,
- frame = (pos * this.totalFrames).round();
- if (frame > this.currentFrame) {
- this.render(pos);
- this.currentFrame = frame;
- }
- }
- },
- cancel: function() {
- if (!this.options.sync)
- Effect.Queues.get(Object.isString(this.options.queue) ?
- 'global' : this.options.queue.scope).remove(this);
- this.state = 'finished';
- },
- event: function(eventName) {
- if (this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
- if (this.options[eventName]) this.options[eventName](this);
- },
- inspect: function() {
- var data = $H();
- for(property in this)
- if (!Object.isFunction(this[property])) data.set(property, this[property]);
- return '#';
- }
-});
-
-Effect.Parallel = Class.create(Effect.Base, {
- initialize: function(effects) {
- this.effects = effects || [];
- this.start(arguments[1]);
- },
- update: function(position) {
- this.effects.invoke('render', position);
- },
- finish: function(position) {
- this.effects.each( function(effect) {
- effect.render(1.0);
- effect.cancel();
- effect.event('beforeFinish');
- if (effect.finish) effect.finish(position);
- effect.event('afterFinish');
- });
- }
-});
-
-Effect.Tween = Class.create(Effect.Base, {
- initialize: function(object, from, to) {
- object = Object.isString(object) ? $(object) : object;
- var args = $A(arguments), method = args.last(),
- options = args.length == 5 ? args[3] : null;
- this.method = Object.isFunction(method) ? method.bind(object) :
- Object.isFunction(object[method]) ? object[method].bind(object) :
- function(value) { object[method] = value };
- this.start(Object.extend({ from: from, to: to }, options || { }));
- },
- update: function(position) {
- this.method(position);
- }
-});
-
-Effect.Event = Class.create(Effect.Base, {
- initialize: function() {
- this.start(Object.extend({ duration: 0 }, arguments[0] || { }));
- },
- update: Prototype.emptyFunction
-});
-
-Effect.Opacity = Class.create(Effect.Base, {
- initialize: function(element) {
- this.element = $(element);
- if (!this.element) throw(Effect._elementDoesNotExistError);
- // make this work on IE on elements without 'layout'
- if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
- this.element.setStyle({zoom: 1});
- var options = Object.extend({
- from: this.element.getOpacity() || 0.0,
- to: 1.0
- }, arguments[1] || { });
- this.start(options);
- },
- update: function(position) {
- this.element.setOpacity(position);
- }
-});
-
-Effect.Move = Class.create(Effect.Base, {
- initialize: function(element) {
- this.element = $(element);
- if (!this.element) throw(Effect._elementDoesNotExistError);
- var options = Object.extend({
- x: 0,
- y: 0,
- mode: 'relative'
- }, arguments[1] || { });
- this.start(options);
- },
- setup: function() {
- this.element.makePositioned();
- this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
- this.originalTop = parseFloat(this.element.getStyle('top') || '0');
- if (this.options.mode == 'absolute') {
- this.options.x = this.options.x - this.originalLeft;
- this.options.y = this.options.y - this.originalTop;
- }
- },
- update: function(position) {
- this.element.setStyle({
- left: (this.options.x * position + this.originalLeft).round() + 'px',
- top: (this.options.y * position + this.originalTop).round() + 'px'
- });
- }
-});
-
-// for backwards compatibility
-Effect.MoveBy = function(element, toTop, toLeft) {
- return new Effect.Move(element,
- Object.extend({ x: toLeft, y: toTop }, arguments[3] || { }));
-};
-
-Effect.Scale = Class.create(Effect.Base, {
- initialize: function(element, percent) {
- this.element = $(element);
- if (!this.element) throw(Effect._elementDoesNotExistError);
- var options = Object.extend({
- scaleX: true,
- scaleY: true,
- scaleContent: true,
- scaleFromCenter: false,
- scaleMode: 'box', // 'box' or 'contents' or { } with provided values
- scaleFrom: 100.0,
- scaleTo: percent
- }, arguments[2] || { });
- this.start(options);
- },
- setup: function() {
- this.restoreAfterFinish = this.options.restoreAfterFinish || false;
- this.elementPositioning = this.element.getStyle('position');
-
- this.originalStyle = { };
- ['top','left','width','height','fontSize'].each( function(k) {
- this.originalStyle[k] = this.element.style[k];
- }.bind(this));
-
- this.originalTop = this.element.offsetTop;
- this.originalLeft = this.element.offsetLeft;
-
- var fontSize = this.element.getStyle('font-size') || '100%';
- ['em','px','%','pt'].each( function(fontSizeType) {
- if (fontSize.indexOf(fontSizeType)>0) {
- this.fontSize = parseFloat(fontSize);
- this.fontSizeType = fontSizeType;
- }
- }.bind(this));
-
- this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
-
- this.dims = null;
- if (this.options.scaleMode=='box')
- this.dims = [this.element.offsetHeight, this.element.offsetWidth];
- if (/^content/.test(this.options.scaleMode))
- this.dims = [this.element.scrollHeight, this.element.scrollWidth];
- if (!this.dims)
- this.dims = [this.options.scaleMode.originalHeight,
- this.options.scaleMode.originalWidth];
- },
- update: function(position) {
- var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
- if (this.options.scaleContent && this.fontSize)
- this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
- this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
- },
- finish: function(position) {
- if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
- },
- setDimensions: function(height, width) {
- var d = { };
- if (this.options.scaleX) d.width = width.round() + 'px';
- if (this.options.scaleY) d.height = height.round() + 'px';
- if (this.options.scaleFromCenter) {
- var topd = (height - this.dims[0])/2;
- var leftd = (width - this.dims[1])/2;
- if (this.elementPositioning == 'absolute') {
- if (this.options.scaleY) d.top = this.originalTop-topd + 'px';
- if (this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
- } else {
- if (this.options.scaleY) d.top = -topd + 'px';
- if (this.options.scaleX) d.left = -leftd + 'px';
- }
- }
- this.element.setStyle(d);
- }
-});
-
-Effect.Highlight = Class.create(Effect.Base, {
- initialize: function(element) {
- this.element = $(element);
- if (!this.element) throw(Effect._elementDoesNotExistError);
- var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || { });
- this.start(options);
- },
- setup: function() {
- // Prevent executing on elements not in the layout flow
- if (this.element.getStyle('display')=='none') { this.cancel(); return; }
- // Disable background image during the effect
- this.oldStyle = { };
- if (!this.options.keepBackgroundImage) {
- this.oldStyle.backgroundImage = this.element.getStyle('background-image');
- this.element.setStyle({backgroundImage: 'none'});
- }
- if (!this.options.endcolor)
- this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
- if (!this.options.restorecolor)
- this.options.restorecolor = this.element.getStyle('background-color');
- // init color calculations
- this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
- this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
- },
- update: function(position) {
- this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
- return m+((this._base[i]+(this._delta[i]*position)).round().toColorPart()); }.bind(this)) });
- },
- finish: function() {
- this.element.setStyle(Object.extend(this.oldStyle, {
- backgroundColor: this.options.restorecolor
- }));
- }
-});
-
-Effect.ScrollTo = function(element) {
- var options = arguments[1] || { },
- scrollOffsets = document.viewport.getScrollOffsets(),
- elementOffsets = $(element).cumulativeOffset();
-
- if (options.offset) elementOffsets[1] += options.offset;
-
- return new Effect.Tween(null,
- scrollOffsets.top,
- elementOffsets[1],
- options,
- function(p){ scrollTo(scrollOffsets.left, p.round()); }
- );
-};
-
-/* ------------- combination effects ------------- */
-
-Effect.Fade = function(element) {
- element = $(element);
- var oldOpacity = element.getInlineOpacity();
- var options = Object.extend({
- from: element.getOpacity() || 1.0,
- to: 0.0,
- afterFinishInternal: function(effect) {
- if (effect.options.to!=0) return;
- effect.element.hide().setStyle({opacity: oldOpacity});
- }
- }, arguments[1] || { });
- return new Effect.Opacity(element,options);
-};
-
-Effect.Appear = function(element) {
- element = $(element);
- var options = Object.extend({
- from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),
- to: 1.0,
- // force Safari to render floated elements properly
- afterFinishInternal: function(effect) {
- effect.element.forceRerendering();
- },
- beforeSetup: function(effect) {
- effect.element.setOpacity(effect.options.from).show();
- }}, arguments[1] || { });
- return new Effect.Opacity(element,options);
-};
-
-Effect.Puff = function(element) {
- element = $(element);
- var oldStyle = {
- opacity: element.getInlineOpacity(),
- position: element.getStyle('position'),
- top: element.style.top,
- left: element.style.left,
- width: element.style.width,
- height: element.style.height
- };
- return new Effect.Parallel(
- [ new Effect.Scale(element, 200,
- { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
- new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
- Object.extend({ duration: 1.0,
- beforeSetupInternal: function(effect) {
- Position.absolutize(effect.effects[0].element);
- },
- afterFinishInternal: function(effect) {
- effect.effects[0].element.hide().setStyle(oldStyle); }
- }, arguments[1] || { })
- );
-};
-
-Effect.BlindUp = function(element) {
- element = $(element);
- element.makeClipping();
- return new Effect.Scale(element, 0,
- Object.extend({ scaleContent: false,
- scaleX: false,
- restoreAfterFinish: true,
- afterFinishInternal: function(effect) {
- effect.element.hide().undoClipping();
- }
- }, arguments[1] || { })
- );
-};
-
-Effect.BlindDown = function(element) {
- element = $(element);
- var elementDimensions = element.getDimensions();
- return new Effect.Scale(element, 100, Object.extend({
- scaleContent: false,
- scaleX: false,
- scaleFrom: 0,
- scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
- restoreAfterFinish: true,
- afterSetup: function(effect) {
- effect.element.makeClipping().setStyle({height: '0px'}).show();
- },
- afterFinishInternal: function(effect) {
- effect.element.undoClipping();
- }
- }, arguments[1] || { }));
-};
-
-Effect.SwitchOff = function(element) {
- element = $(element);
- var oldOpacity = element.getInlineOpacity();
- return new Effect.Appear(element, Object.extend({
- duration: 0.4,
- from: 0,
- transition: Effect.Transitions.flicker,
- afterFinishInternal: function(effect) {
- new Effect.Scale(effect.element, 1, {
- duration: 0.3, scaleFromCenter: true,
- scaleX: false, scaleContent: false, restoreAfterFinish: true,
- beforeSetup: function(effect) {
- effect.element.makePositioned().makeClipping();
- },
- afterFinishInternal: function(effect) {
- effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
- }
- });
- }
- }, arguments[1] || { }));
-};
-
-Effect.DropOut = function(element) {
- element = $(element);
- var oldStyle = {
- top: element.getStyle('top'),
- left: element.getStyle('left'),
- opacity: element.getInlineOpacity() };
- return new Effect.Parallel(
- [ new Effect.Move(element, {x: 0, y: 100, sync: true }),
- new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
- Object.extend(
- { duration: 0.5,
- beforeSetup: function(effect) {
- effect.effects[0].element.makePositioned();
- },
- afterFinishInternal: function(effect) {
- effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
- }
- }, arguments[1] || { }));
-};
-
-Effect.Shake = function(element) {
- element = $(element);
- var options = Object.extend({
- distance: 20,
- duration: 0.5
- }, arguments[1] || {});
- var distance = parseFloat(options.distance);
- var split = parseFloat(options.duration) / 10.0;
- var oldStyle = {
- top: element.getStyle('top'),
- left: element.getStyle('left') };
- return new Effect.Move(element,
- { x: distance, y: 0, duration: split, afterFinishInternal: function(effect) {
- new Effect.Move(effect.element,
- { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
- new Effect.Move(effect.element,
- { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
- new Effect.Move(effect.element,
- { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
- new Effect.Move(effect.element,
- { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
- new Effect.Move(effect.element,
- { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) {
- effect.element.undoPositioned().setStyle(oldStyle);
- }}); }}); }}); }}); }}); }});
-};
-
-Effect.SlideDown = function(element) {
- element = $(element).cleanWhitespace();
- // SlideDown need to have the content of the element wrapped in a container element with fixed height!
- var oldInnerBottom = element.down().getStyle('bottom');
- var elementDimensions = element.getDimensions();
- return new Effect.Scale(element, 100, Object.extend({
- scaleContent: false,
- scaleX: false,
- scaleFrom: window.opera ? 0 : 1,
- scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
- restoreAfterFinish: true,
- afterSetup: function(effect) {
- effect.element.makePositioned();
- effect.element.down().makePositioned();
- if (window.opera) effect.element.setStyle({top: ''});
- effect.element.makeClipping().setStyle({height: '0px'}).show();
- },
- afterUpdateInternal: function(effect) {
- effect.element.down().setStyle({bottom:
- (effect.dims[0] - effect.element.clientHeight) + 'px' });
- },
- afterFinishInternal: function(effect) {
- effect.element.undoClipping().undoPositioned();
- effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
- }, arguments[1] || { })
- );
-};
-
-Effect.SlideUp = function(element) {
- element = $(element).cleanWhitespace();
- var oldInnerBottom = element.down().getStyle('bottom');
- var elementDimensions = element.getDimensions();
- return new Effect.Scale(element, window.opera ? 0 : 1,
- Object.extend({ scaleContent: false,
- scaleX: false,
- scaleMode: 'box',
- scaleFrom: 100,
- scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
- restoreAfterFinish: true,
- afterSetup: function(effect) {
- effect.element.makePositioned();
- effect.element.down().makePositioned();
- if (window.opera) effect.element.setStyle({top: ''});
- effect.element.makeClipping().show();
- },
- afterUpdateInternal: function(effect) {
- effect.element.down().setStyle({bottom:
- (effect.dims[0] - effect.element.clientHeight) + 'px' });
- },
- afterFinishInternal: function(effect) {
- effect.element.hide().undoClipping().undoPositioned();
- effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom});
- }
- }, arguments[1] || { })
- );
-};
-
-// Bug in opera makes the TD containing this element expand for a instance after finish
-Effect.Squish = function(element) {
- return new Effect.Scale(element, window.opera ? 1 : 0, {
- restoreAfterFinish: true,
- beforeSetup: function(effect) {
- effect.element.makeClipping();
- },
- afterFinishInternal: function(effect) {
- effect.element.hide().undoClipping();
- }
- });
-};
-
-Effect.Grow = function(element) {
- element = $(element);
- var options = Object.extend({
- direction: 'center',
- moveTransition: Effect.Transitions.sinoidal,
- scaleTransition: Effect.Transitions.sinoidal,
- opacityTransition: Effect.Transitions.full
- }, arguments[1] || { });
- var oldStyle = {
- top: element.style.top,
- left: element.style.left,
- height: element.style.height,
- width: element.style.width,
- opacity: element.getInlineOpacity() };
-
- var dims = element.getDimensions();
- var initialMoveX, initialMoveY;
- var moveX, moveY;
-
- switch (options.direction) {
- case 'top-left':
- initialMoveX = initialMoveY = moveX = moveY = 0;
- break;
- case 'top-right':
- initialMoveX = dims.width;
- initialMoveY = moveY = 0;
- moveX = -dims.width;
- break;
- case 'bottom-left':
- initialMoveX = moveX = 0;
- initialMoveY = dims.height;
- moveY = -dims.height;
- break;
- case 'bottom-right':
- initialMoveX = dims.width;
- initialMoveY = dims.height;
- moveX = -dims.width;
- moveY = -dims.height;
- break;
- case 'center':
- initialMoveX = dims.width / 2;
- initialMoveY = dims.height / 2;
- moveX = -dims.width / 2;
- moveY = -dims.height / 2;
- break;
- }
-
- return new Effect.Move(element, {
- x: initialMoveX,
- y: initialMoveY,
- duration: 0.01,
- beforeSetup: function(effect) {
- effect.element.hide().makeClipping().makePositioned();
- },
- afterFinishInternal: function(effect) {
- new Effect.Parallel(
- [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
- new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
- new Effect.Scale(effect.element, 100, {
- scaleMode: { originalHeight: dims.height, originalWidth: dims.width },
- sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
- ], Object.extend({
- beforeSetup: function(effect) {
- effect.effects[0].element.setStyle({height: '0px'}).show();
- },
- afterFinishInternal: function(effect) {
- effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);
- }
- }, options)
- );
- }
- });
-};
-
-Effect.Shrink = function(element) {
- element = $(element);
- var options = Object.extend({
- direction: 'center',
- moveTransition: Effect.Transitions.sinoidal,
- scaleTransition: Effect.Transitions.sinoidal,
- opacityTransition: Effect.Transitions.none
- }, arguments[1] || { });
- var oldStyle = {
- top: element.style.top,
- left: element.style.left,
- height: element.style.height,
- width: element.style.width,
- opacity: element.getInlineOpacity() };
-
- var dims = element.getDimensions();
- var moveX, moveY;
-
- switch (options.direction) {
- case 'top-left':
- moveX = moveY = 0;
- break;
- case 'top-right':
- moveX = dims.width;
- moveY = 0;
- break;
- case 'bottom-left':
- moveX = 0;
- moveY = dims.height;
- break;
- case 'bottom-right':
- moveX = dims.width;
- moveY = dims.height;
- break;
- case 'center':
- moveX = dims.width / 2;
- moveY = dims.height / 2;
- break;
- }
-
- return new Effect.Parallel(
- [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
- new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
- new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
- ], Object.extend({
- beforeStartInternal: function(effect) {
- effect.effects[0].element.makePositioned().makeClipping();
- },
- afterFinishInternal: function(effect) {
- effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
- }, options)
- );
-};
-
-Effect.Pulsate = function(element) {
- element = $(element);
- var options = arguments[1] || { },
- oldOpacity = element.getInlineOpacity(),
- transition = options.transition || Effect.Transitions.linear,
- reverser = function(pos){
- return 1 - transition((-Math.cos((pos*(options.pulses||5)*2)*Math.PI)/2) + .5);
- };
-
- return new Effect.Opacity(element,
- Object.extend(Object.extend({ duration: 2.0, from: 0,
- afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
- }, options), {transition: reverser}));
-};
-
-Effect.Fold = function(element) {
- element = $(element);
- var oldStyle = {
- top: element.style.top,
- left: element.style.left,
- width: element.style.width,
- height: element.style.height };
- element.makeClipping();
- return new Effect.Scale(element, 5, Object.extend({
- scaleContent: false,
- scaleX: false,
- afterFinishInternal: function(effect) {
- new Effect.Scale(element, 1, {
- scaleContent: false,
- scaleY: false,
- afterFinishInternal: function(effect) {
- effect.element.hide().undoClipping().setStyle(oldStyle);
- } });
- }}, arguments[1] || { }));
-};
-
-Effect.Morph = Class.create(Effect.Base, {
- initialize: function(element) {
- this.element = $(element);
- if (!this.element) throw(Effect._elementDoesNotExistError);
- var options = Object.extend({
- style: { }
- }, arguments[1] || { });
-
- if (!Object.isString(options.style)) this.style = $H(options.style);
- else {
- if (options.style.include(':'))
- this.style = options.style.parseStyle();
- else {
- this.element.addClassName(options.style);
- this.style = $H(this.element.getStyles());
- this.element.removeClassName(options.style);
- var css = this.element.getStyles();
- this.style = this.style.reject(function(style) {
- return style.value == css[style.key];
- });
- options.afterFinishInternal = function(effect) {
- effect.element.addClassName(effect.options.style);
- effect.transforms.each(function(transform) {
- effect.element.style[transform.style] = '';
- });
- };
- }
- }
- this.start(options);
- },
-
- setup: function(){
- function parseColor(color){
- if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
- color = color.parseColor();
- return $R(0,2).map(function(i){
- return parseInt( color.slice(i*2+1,i*2+3), 16 );
- });
- }
- this.transforms = this.style.map(function(pair){
- var property = pair[0], value = pair[1], unit = null;
-
- if (value.parseColor('#zzzzzz') != '#zzzzzz') {
- value = value.parseColor();
- unit = 'color';
- } else if (property == 'opacity') {
- value = parseFloat(value);
- if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
- this.element.setStyle({zoom: 1});
- } else if (Element.CSS_LENGTH.test(value)) {
- var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
- value = parseFloat(components[1]);
- unit = (components.length == 3) ? components[2] : null;
- }
-
- var originalValue = this.element.getStyle(property);
- return {
- style: property.camelize(),
- originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0),
- targetValue: unit=='color' ? parseColor(value) : value,
- unit: unit
- };
- }.bind(this)).reject(function(transform){
- return (
- (transform.originalValue == transform.targetValue) ||
- (
- transform.unit != 'color' &&
- (isNaN(transform.originalValue) || isNaN(transform.targetValue))
- )
- );
- });
- },
- update: function(position) {
- var style = { }, transform, i = this.transforms.length;
- while(i--)
- style[(transform = this.transforms[i]).style] =
- transform.unit=='color' ? '#'+
- (Math.round(transform.originalValue[0]+
- (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() +
- (Math.round(transform.originalValue[1]+
- (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() +
- (Math.round(transform.originalValue[2]+
- (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() :
- (transform.originalValue +
- (transform.targetValue - transform.originalValue) * position).toFixed(3) +
- (transform.unit === null ? '' : transform.unit);
- this.element.setStyle(style, true);
- }
-});
-
-Effect.Transform = Class.create({
- initialize: function(tracks){
- this.tracks = [];
- this.options = arguments[1] || { };
- this.addTracks(tracks);
- },
- addTracks: function(tracks){
- tracks.each(function(track){
- track = $H(track);
- var data = track.values().first();
- this.tracks.push($H({
- ids: track.keys().first(),
- effect: Effect.Morph,
- options: { style: data }
- }));
- }.bind(this));
- return this;
- },
- play: function(){
- return new Effect.Parallel(
- this.tracks.map(function(track){
- var ids = track.get('ids'), effect = track.get('effect'), options = track.get('options');
- var elements = [$(ids) || $$(ids)].flatten();
- return elements.map(function(e){ return new effect(e, Object.extend({ sync:true }, options)) });
- }).flatten(),
- this.options
- );
- }
-});
-
-Element.CSS_PROPERTIES = $w(
- 'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' +
- 'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
- 'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
- 'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
- 'fontSize fontWeight height left letterSpacing lineHeight ' +
- 'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
- 'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
- 'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
- 'right textIndent top width wordSpacing zIndex');
-
-Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
-
-String.__parseStyleElement = document.createElement('div');
-String.prototype.parseStyle = function(){
- var style, styleRules = $H();
- if (Prototype.Browser.WebKit)
- style = new Element('div',{style:this}).style;
- else {
- String.__parseStyleElement.innerHTML = '
';
- style = String.__parseStyleElement.childNodes[0].style;
- }
-
- Element.CSS_PROPERTIES.each(function(property){
- if (style[property]) styleRules.set(property, style[property]);
- });
-
- if (Prototype.Browser.IE && this.include('opacity'))
- styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]);
-
- return styleRules;
-};
-
-if (document.defaultView && document.defaultView.getComputedStyle) {
- Element.getStyles = function(element) {
- var css = document.defaultView.getComputedStyle($(element), null);
- return Element.CSS_PROPERTIES.inject({ }, function(styles, property) {
- styles[property] = css[property];
- return styles;
- });
- };
-} else {
- Element.getStyles = function(element) {
- element = $(element);
- var css = element.currentStyle, styles;
- styles = Element.CSS_PROPERTIES.inject({ }, function(results, property) {
- results[property] = css[property];
- return results;
- });
- if (!styles.opacity) styles.opacity = element.getOpacity();
- return styles;
- };
-}
-
-Effect.Methods = {
- morph: function(element, style) {
- element = $(element);
- new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { }));
- return element;
- },
- visualEffect: function(element, effect, options) {
- element = $(element);
- var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1);
- new Effect[klass](element, options);
- return element;
- },
- highlight: function(element, options) {
- element = $(element);
- new Effect.Highlight(element, options);
- return element;
- }
-};
-
-$w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+
- 'pulsate shake puff squish switchOff dropOut').each(
- function(effect) {
- Effect.Methods[effect] = function(element, options){
- element = $(element);
- Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options);
- return element;
- };
- }
-);
-
-$w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each(
- function(f) { Effect.Methods[f] = Element[f]; }
-);
-
-Element.addMethods(Effect.Methods);
\ No newline at end of file
diff --git a/public/javascripts/ordering.js b/public/javascripts/ordering.js
deleted file mode 100644
index e72d1abf..00000000
--- a/public/javascripts/ordering.js
+++ /dev/null
@@ -1,205 +0,0 @@
-// JavaScript that handles the dynamic ordering quantities on the ordering page.
-//
-// In a JavaScript block on the actual view, define the article data by calls to setData().
-// You should also set the available group balance through setGroupBalance(amount).
-//
-// Call setDecimalSeparator(char) to overwrite the default character "." with a localized value.
-
-var modified = false // indicates if anything has been clicked on this page
-var groupBalance = 0; // available group money
-var decimalSeparator = "."; // default decimal separator
-var toleranceIsCostly = true; // default tolerance behaviour
-
-// Article data arrays:
-var price = new Array();
-var unit = new Array(); // items per order unit
-var itemTotal = new Array(); // total item price
-var quantityOthers = new Array();
-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 setDecimalSeparator(character) {
- decimalSeparator = character;
-}
-
-function setToleranceBehaviour(value) {
- toleranceIsCostly = value;
-}
-
-function setGroupBalance(amount) {
- groupBalance = amount;
-}
-
-function addData(itemPrice, itemUnit, itemSubtotal, itemQuantityOthers, itemToleranceOthers, allocated, available) {
- i = price.length;
- price[i] = itemPrice;
- unit[i] = itemUnit;
- itemTotal[i] = itemSubtotal;
- quantityOthers[i] = itemQuantityOthers;
- toleranceOthers[i] = itemToleranceOthers;
- itemsAllocated[i] = allocated;
- quantityAvailable[i] = available;
-}
-
-function increaseQuantity(item) {
- value = Number($('q_' + item).value) + 1;
- update(item, value, $('t_' + item).value);
-}
-
-function decreaseQuantity(item) {
- value = Number($('q_' + item).value) - 1;
- if (value >= 0) {
- update(item, value, $('t_' + item).value);
- }
-}
-
-function increaseTolerance(item) {
- value = Number($('t_' + item).value) + 1;
- update(item, $('q_' + item).value, value);
-}
-
-function decreaseTolerance(item) {
- value = Number($('t_' + item).value) - 1;
- if (value >= 0) {
- update(item, $('q_' + item).value, value);
- }
-}
-
-function update(item, quantity, tolerance) {
- // set modification flag
- modified = true
-
- // update hidden input fields
- $('q_' + item).value = quantity;
- $('t_' + item).value = tolerance;
-
- // calculate how many units would be ordered in total
- units = calcUnits(unit[item], quantityOthers[item] + Number(quantity), toleranceOthers[item] + Number(tolerance));
- if (unitCompletedFromTolerance(unit[item], quantityOthers[item] + Number(quantity), toleranceOthers[item] + Number(tolerance))) {
- $('units_' + item).update('' + String(units) + " ");
- } else {
- $('units_' + item).update(String(units));
- }
-
- // update used/unused quantity
- available = Math.max(0, units * unit[item] - quantityOthers[item]);
- q_used = Math.min(available, quantity);
- // ensure that at least the amout of items this group has already been allocated is used
- if (quantity >= itemsAllocated[item] && q_used < itemsAllocated[item]) {
- q_used = itemsAllocated[item];
- }
- $('q_used_' + item).update(String(q_used));
- $('q_unused_' + item).update(String(quantity - q_used));
- $('q_total_' + item).update(String(Number(quantity) + quantityOthers[item]));
-
- // update used/unused tolerance
- if (unit[item] > 1) {
- available = Math.max(0, available - q_used - toleranceOthers[item]);
- t_used = Math.min(available, tolerance);
- $('t_used_' + item).update(String(t_used));
- $('t_unused_' + item).update(String(tolerance - t_used));
- $('t_total_' + item).update(String(Number(tolerance) + toleranceOthers[item]));
- }
-
- // update total price
- if(toleranceIsCostly == true) {
- itemTotal[item] = price[item] * (Number(quantity) + Number(tolerance));
- } else {
- itemTotal[item] = price[item] * (Number(quantity));
- }
- $('price_' + item + '_display').update(asMoney(itemTotal[item]));
-
- // update missing units
- missing_units = unit[item] - (((quantityOthers[item] + Number(quantity)) % unit[item]) + Number(tolerance) + toleranceOthers[item])
- if (missing_units < 0) {
- missing_units = 0;
- }
- $('missing_units_' + item).update(String(missing_units));
-
- // update balance
- updateBalance();
-}
-
-function increaseStockQuantity(item) {
- value = Number($('q_' + item).value) + 1;
- if (value <= quantityAvailable[item] - quantityOthers[item]) {
- updateStockQuantity(item, value);
- }
-}
-
-function decreaseStockQuantity(item) {
- value = Number($('q_' + item).value) - 1;
- if (value >= 0) {
- updateStockQuantity(item, value);
- }
-}
-
-function updateStockQuantity(item, quantity) {
- // set modification flag
- modified = true
-
- // update hidden input fields
- $('q_' + item).value = quantity;
-
- // update used/unused quantity
- available = Math.max(0, quantityAvailable[item] - quantityOthers[item]);
- q_used = Math.min(available, quantity);
-
- // ensure that at least the amout of items this group has already been allocated is used
- if (quantity >= itemsAllocated[item] && q_used < itemsAllocated[item]) {
- q_used = itemsAllocated[item];
- }
- $('q_used_' + item).update(String(q_used));
- $('q_total_' + item).update(String(Number(quantity) + quantityOthers[item]));
-
- // update total price
- itemTotal[item] = price[item] * (Number(quantity));
- $('price_' + item + '_display').update(asMoney(itemTotal[item]));
-
- // update balance
- updateBalance();
-}
-
-function asMoney(amount) {
- return String(amount.toFixed(2)).replace(/\./, ",");
-}
-
-function calcUnits(unitSize, quantity, tolerance) {
- units = Math.floor(quantity / unitSize)
- remainder = quantity % unitSize
- return units + ((remainder > 0) && (remainder + tolerance >= unitSize) ? 1 : 0)
-}
-
-function unitCompletedFromTolerance(unitSize, quantity, tolerance) {
- remainder = quantity % unitSize
- return (remainder > 0 && (remainder + tolerance >= unitSize));
-}
-
-function updateBalance() {
- // update total price and order balance
- total = 0;
- for (i = 0; i < itemTotal.length; i++) {
- total += itemTotal[i];
- }
- $('total_price').update(asMoney(total));
- balance = groupBalance - total;
- $('new_balance').update(asMoney(balance));
- $('total_balance').value = asMoney(balance);
- // determine bgcolor and submit button state according to balance
- if (balance < 0) {
- bgcolor = '#FF0000';
- $('submit_button').disabled = true;
- } else {
- bgcolor = '';
- $('submit_button').disabled = false;
- }
- // update bgcolor
- for (i = 0; i < itemTotal.length; i++) {
- $('td_price_' + i).style.backgroundColor = bgcolor;
- }
-}
-
-function confirmSwitchOrder() {
- return (!modified || confirm('Änderungen an dieser Bestellung gehen verloren, wenn zu einer anderen Bestellung gewechselt wird.'))
-}
diff --git a/public/javascripts/prototype.js b/public/javascripts/prototype.js
deleted file mode 100644
index dfe8ab4e..00000000
--- a/public/javascripts/prototype.js
+++ /dev/null
@@ -1,4320 +0,0 @@
-/* Prototype JavaScript framework, version 1.6.0.3
- * (c) 2005-2008 Sam Stephenson
- *
- * Prototype is freely distributable under the terms of an MIT-style license.
- * For details, see the Prototype web site: http://www.prototypejs.org/
- *
- *--------------------------------------------------------------------------*/
-
-var Prototype = {
- Version: '1.6.0.3',
-
- Browser: {
- IE: !!(window.attachEvent &&
- navigator.userAgent.indexOf('Opera') === -1),
- Opera: navigator.userAgent.indexOf('Opera') > -1,
- WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
- Gecko: navigator.userAgent.indexOf('Gecko') > -1 &&
- navigator.userAgent.indexOf('KHTML') === -1,
- MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
- },
-
- BrowserFeatures: {
- XPath: !!document.evaluate,
- SelectorsAPI: !!document.querySelector,
- ElementExtensions: !!window.HTMLElement,
- SpecificElementExtensions:
- document.createElement('div')['__proto__'] &&
- document.createElement('div')['__proto__'] !==
- document.createElement('form')['__proto__']
- },
-
- ScriptFragment: '),
- auto_complete_field("some_input", :url => { :action => "autocomplete" });
- assert_dom_equal %(),
- auto_complete_field("some_input", :url => { :action => "autocomplete" }, :tokens => ',');
- assert_dom_equal %(),
- auto_complete_field("some_input", :url => { :action => "autocomplete" }, :tokens => [',']);
- assert_dom_equal %(),
- auto_complete_field("some_input", :url => { :action => "autocomplete" }, :min_chars => 3);
- assert_dom_equal %(),
- auto_complete_field("some_input", :url => { :action => "autocomplete" }, :on_hide => "function(element, update){alert('me');}");
- assert_dom_equal %(),
- auto_complete_field("some_input", :url => { :action => "autocomplete" }, :frequency => 2);
- assert_dom_equal %(),
- auto_complete_field("some_input", :url => { :action => "autocomplete" },
- :after_update_element => "function(element,value){alert('You have chosen: '+value)}");
- assert_dom_equal %(),
- auto_complete_field("some_input", :url => { :action => "autocomplete" }, :param_name => 'huidriwusch');
- assert_dom_equal %(),
- auto_complete_field("some_input", :url => { :action => "autocomplete" }, :method => :get);
- end
-
- def test_auto_complete_result
- result = [ { :title => 'test1' }, { :title => 'test2' } ]
- assert_equal %(),
- auto_complete_result(result, :title)
- assert_equal %(),
- auto_complete_result(result, :title, "est")
-
- resultuniq = [ { :title => 'test1' }, { :title => 'test1' } ]
- assert_equal %(),
- auto_complete_result(resultuniq, :title, "est")
- end
-
- def test_text_field_with_auto_complete
- assert_match %(
-
-
- Samples of pagination styling for will_paginate
-
- Find these styles in "examples/pagination.css" of will_paginate library.
- There is a Sass version of it for all you sassy people.
-
-
- Read about good rules for pagination:
- Pagination 101
-
-
- Warning:
- page links below don't lead anywhere (so don't click on them).
-
-
- Unstyled pagination (ewww! )
-
-
- Digg.com
-
- Digg-style, no page links
-
- Code that renders this:
-
- <%= will_paginate @posts, :page_links => false %>
-
- Digg-style, extra content
-
- Code that renders this:
-
- <div class="digg_pagination">
- <div clas="page_info">
- <%= page_entries_info @posts %>
- </div>
- <%= will_paginate @posts, :container => false %>
- </div>
-
- Apple.com store
-
- Flickr.com
-
-
diff --git a/vendor/plugins/will_paginate/examples/pagination.css b/vendor/plugins/will_paginate/examples/pagination.css
deleted file mode 100644
index b55e9779..00000000
--- a/vendor/plugins/will_paginate/examples/pagination.css
+++ /dev/null
@@ -1,90 +0,0 @@
-.digg_pagination {
- background: white;
- /* self-clearing method: */ }
- .digg_pagination a, .digg_pagination span {
- padding: .2em .5em;
- display: block;
- float: left;
- margin-right: 1px; }
- .digg_pagination span.disabled {
- color: #999;
- border: 1px solid #DDD; }
- .digg_pagination span.current {
- font-weight: bold;
- background: #2E6AB1;
- color: white;
- border: 1px solid #2E6AB1; }
- .digg_pagination a {
- text-decoration: none;
- color: #105CB6;
- border: 1px solid #9AAFE5; }
- .digg_pagination a:hover, .digg_pagination a:focus {
- color: #003;
- border-color: #003; }
- .digg_pagination .page_info {
- background: #2E6AB1;
- color: white;
- padding: .4em .6em;
- width: 22em;
- margin-bottom: .3em;
- text-align: center; }
- .digg_pagination .page_info b {
- color: #003;
- background: #6aa6ed;
- padding: .1em .25em; }
- .digg_pagination:after {
- content: ".";
- display: block;
- height: 0;
- clear: both;
- visibility: hidden; }
- * html .digg_pagination {
- height: 1%; }
- *:first-child+html .digg_pagination {
- overflow: hidden; }
-
-.apple_pagination {
- background: #F1F1F1;
- border: 1px solid #E5E5E5;
- text-align: center;
- padding: 1em; }
- .apple_pagination a, .apple_pagination span {
- padding: .2em .3em; }
- .apple_pagination span.disabled {
- color: #AAA; }
- .apple_pagination span.current {
- font-weight: bold;
- background: transparent url(apple-circle.gif) no-repeat 50% 50%; }
- .apple_pagination a {
- text-decoration: none;
- color: black; }
- .apple_pagination a:hover, .apple_pagination a:focus {
- text-decoration: underline; }
-
-.flickr_pagination {
- text-align: center;
- padding: .3em; }
- .flickr_pagination a, .flickr_pagination span {
- padding: .2em .5em; }
- .flickr_pagination span.disabled {
- color: #AAA; }
- .flickr_pagination span.current {
- font-weight: bold;
- color: #FF0084; }
- .flickr_pagination a {
- border: 1px solid #DDDDDD;
- color: #0063DC;
- text-decoration: none; }
- .flickr_pagination a:hover, .flickr_pagination a:focus {
- border-color: #003366;
- background: #0063DC;
- color: white; }
- .flickr_pagination .page_info {
- color: #aaa;
- padding-top: .8em; }
- .flickr_pagination .prev_page, .flickr_pagination .next_page {
- border-width: 2px; }
- .flickr_pagination .prev_page {
- margin-right: 1em; }
- .flickr_pagination .next_page {
- margin-left: 1em; }
diff --git a/vendor/plugins/will_paginate/examples/pagination.sass b/vendor/plugins/will_paginate/examples/pagination.sass
deleted file mode 100644
index 737a97be..00000000
--- a/vendor/plugins/will_paginate/examples/pagination.sass
+++ /dev/null
@@ -1,91 +0,0 @@
-.digg_pagination
- :background white
- a, span
- :padding .2em .5em
- :display block
- :float left
- :margin-right 1px
- span.disabled
- :color #999
- :border 1px solid #DDD
- span.current
- :font-weight bold
- :background #2E6AB1
- :color white
- :border 1px solid #2E6AB1
- a
- :text-decoration none
- :color #105CB6
- :border 1px solid #9AAFE5
- &:hover, &:focus
- :color #003
- :border-color #003
- .page_info
- :background #2E6AB1
- :color white
- :padding .4em .6em
- :width 22em
- :margin-bottom .3em
- :text-align center
- b
- :color #003
- :background = #2E6AB1 + 60
- :padding .1em .25em
-
- /* self-clearing method:
- &:after
- :content "."
- :display block
- :height 0
- :clear both
- :visibility hidden
- * html &
- :height 1%
- *:first-child+html &
- :overflow hidden
-
-.apple_pagination
- :background #F1F1F1
- :border 1px solid #E5E5E5
- :text-align center
- :padding 1em
- a, span
- :padding .2em .3em
- span.disabled
- :color #AAA
- span.current
- :font-weight bold
- :background transparent url(apple-circle.gif) no-repeat 50% 50%
- a
- :text-decoration none
- :color black
- &:hover, &:focus
- :text-decoration underline
-
-.flickr_pagination
- :text-align center
- :padding .3em
- a, span
- :padding .2em .5em
- span.disabled
- :color #AAA
- span.current
- :font-weight bold
- :color #FF0084
- a
- :border 1px solid #DDDDDD
- :color #0063DC
- :text-decoration none
- &:hover, &:focus
- :border-color #003366
- :background #0063DC
- :color white
- .page_info
- :color #aaa
- :padding-top .8em
- .prev_page, .next_page
- :border-width 2px
- .prev_page
- :margin-right 1em
- .next_page
- :margin-left 1em
diff --git a/vendor/plugins/will_paginate/init.rb b/vendor/plugins/will_paginate/init.rb
deleted file mode 100644
index 838d30ec..00000000
--- a/vendor/plugins/will_paginate/init.rb
+++ /dev/null
@@ -1 +0,0 @@
-require 'will_paginate'
diff --git a/vendor/plugins/will_paginate/lib/will_paginate.rb b/vendor/plugins/will_paginate/lib/will_paginate.rb
deleted file mode 100644
index 1b633f16..00000000
--- a/vendor/plugins/will_paginate/lib/will_paginate.rb
+++ /dev/null
@@ -1,82 +0,0 @@
-require 'active_support'
-
-# = You *will* paginate!
-#
-# First read about WillPaginate::Finder::ClassMethods, then see
-# WillPaginate::ViewHelpers. The magical array you're handling in-between is
-# WillPaginate::Collection.
-#
-# Happy paginating!
-module WillPaginate
- class << self
- # shortcut for enable_actionpack and enable_activerecord combined
- def enable
- enable_actionpack
- enable_activerecord
- end
-
- # hooks WillPaginate::ViewHelpers into ActionView::Base
- def enable_actionpack
- return if ActionView::Base.instance_methods.include? 'will_paginate'
- require 'will_paginate/view_helpers'
- ActionView::Base.send :include, ViewHelpers
-
- if defined?(ActionController::Base) and ActionController::Base.respond_to? :rescue_responses
- ActionController::Base.rescue_responses['WillPaginate::InvalidPage'] = :not_found
- end
- end
-
- # hooks WillPaginate::Finder into ActiveRecord::Base and classes that deal
- # with associations
- def enable_activerecord
- return if ActiveRecord::Base.respond_to? :paginate
- require 'will_paginate/finder'
- ActiveRecord::Base.send :include, Finder
-
- # support pagination on associations
- a = ActiveRecord::Associations
- returning([ a::AssociationCollection ]) { |classes|
- # detect http://dev.rubyonrails.org/changeset/9230
- unless a::HasManyThroughAssociation.superclass == a::HasManyAssociation
- classes << a::HasManyThroughAssociation
- end
- }.each do |klass|
- klass.send :include, Finder::ClassMethods
- klass.class_eval { alias_method_chain :method_missing, :paginate }
- end
- end
-
- # Enable named_scope, a feature of Rails 2.1, even if you have older Rails
- # (tested on Rails 2.0.2 and 1.2.6).
- #
- # You can pass +false+ for +patch+ parameter to skip monkeypatching
- # *associations*. Use this if you feel that named_scope broke
- # has_many, has_many :through or has_and_belongs_to_many associations in
- # your app. By passing +false+, you can still use named_scope in
- # your models, but not through associations.
- def enable_named_scope(patch = true)
- return if defined? ActiveRecord::NamedScope
- require 'will_paginate/named_scope'
- require 'will_paginate/named_scope_patch' if patch
-
- ActiveRecord::Base.send :include, WillPaginate::NamedScope
- end
- end
-
- module Deprecation # :nodoc:
- extend ActiveSupport::Deprecation
-
- def self.warn(message, callstack = caller)
- message = 'WillPaginate: ' + message.strip.gsub(/\s+/, ' ')
- behavior.call(message, callstack) if behavior && !silenced?
- end
-
- def self.silenced?
- ActiveSupport::Deprecation.silenced?
- end
- end
-end
-
-if defined?(Rails) and defined?(ActiveRecord) and defined?(ActionController)
- WillPaginate.enable
-end
diff --git a/vendor/plugins/will_paginate/lib/will_paginate/array.rb b/vendor/plugins/will_paginate/lib/will_paginate/array.rb
deleted file mode 100644
index d061d2be..00000000
--- a/vendor/plugins/will_paginate/lib/will_paginate/array.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-require 'will_paginate/collection'
-
-# http://www.desimcadam.com/archives/8
-Array.class_eval do
- def paginate(options = {})
- raise ArgumentError, "parameter hash expected (got #{options.inspect})" unless Hash === options
-
- WillPaginate::Collection.create(
- options[:page] || 1,
- options[:per_page] || 30,
- options[:total_entries] || self.length
- ) { |pager|
- pager.replace self[pager.offset, pager.per_page].to_a
- }
- end
-end
diff --git a/vendor/plugins/will_paginate/lib/will_paginate/collection.rb b/vendor/plugins/will_paginate/lib/will_paginate/collection.rb
deleted file mode 100644
index ac0153a1..00000000
--- a/vendor/plugins/will_paginate/lib/will_paginate/collection.rb
+++ /dev/null
@@ -1,146 +0,0 @@
-module WillPaginate
- # = Invalid page number error
- # This is an ArgumentError raised in case a page was requested that is either
- # zero or negative number. You should decide how do deal with such errors in
- # the controller.
- #
- # If you're using Rails 2, then this error will automatically get handled like
- # 404 Not Found. The hook is in "will_paginate.rb":
- #
- # ActionController::Base.rescue_responses['WillPaginate::InvalidPage'] = :not_found
- #
- # If you don't like this, use your preffered method of rescuing exceptions in
- # public from your controllers to handle this differently. The +rescue_from+
- # method is a nice addition to Rails 2.
- #
- # This error is *not* raised when a page further than the last page is
- # requested. Use WillPaginate::Collection#out_of_bounds? method to
- # check for those cases and manually deal with them as you see fit.
- class InvalidPage < ArgumentError
- def initialize(page, page_num)
- super "#{page.inspect} given as value, which translates to '#{page_num}' as page number"
- end
- end
-
- # = The key to pagination
- # Arrays returned from paginating finds are, in fact, instances of this little
- # class. You may think of WillPaginate::Collection as an ordinary array with
- # some extra properties. Those properties are used by view helpers to generate
- # correct page links.
- #
- # WillPaginate::Collection also assists in rolling out your own pagination
- # solutions: see +create+.
- #
- # If you are writing a library that provides a collection which you would like
- # to conform to this API, you don't have to copy these methods over; simply
- # make your plugin/gem dependant on the "mislav-will_paginate" gem:
- #
- # gem 'mislav-will_paginate'
- # require 'will_paginate/collection'
- #
- # # WillPaginate::Collection is now available for use
- class Collection < Array
- attr_reader :current_page, :per_page, :total_entries, :total_pages
-
- # Arguments to the constructor are the current page number, per-page limit
- # and the total number of entries. The last argument is optional because it
- # is best to do lazy counting; in other words, count *conditionally* after
- # populating the collection using the +replace+ method.
- def initialize(page, per_page, total = nil)
- @current_page = page.to_i
- raise InvalidPage.new(page, @current_page) if @current_page < 1
- @per_page = per_page.to_i
- raise ArgumentError, "`per_page` setting cannot be less than 1 (#{@per_page} given)" if @per_page < 1
-
- self.total_entries = total if total
- end
-
- # Just like +new+, but yields the object after instantiation and returns it
- # afterwards. This is very useful for manual pagination:
- #
- # @entries = WillPaginate::Collection.create(1, 10) do |pager|
- # result = Post.find(:all, :limit => pager.per_page, :offset => pager.offset)
- # # inject the result array into the paginated collection:
- # pager.replace(result)
- #
- # unless pager.total_entries
- # # the pager didn't manage to guess the total count, do it manually
- # pager.total_entries = Post.count
- # end
- # end
- #
- # The possibilities with this are endless. For another example, here is how
- # WillPaginate used to define pagination for Array instances:
- #
- # Array.class_eval do
- # def paginate(page = 1, per_page = 15)
- # WillPaginate::Collection.create(page, per_page, size) do |pager|
- # pager.replace self[pager.offset, pager.per_page].to_a
- # end
- # end
- # end
- #
- # The Array#paginate API has since then changed, but this still serves as a
- # fine example of WillPaginate::Collection usage.
- def self.create(page, per_page, total = nil, &block)
- pager = new(page, per_page, total)
- yield pager
- pager
- end
-
- # Helper method that is true when someone tries to fetch a page with a
- # larger number than the last page. Can be used in combination with flashes
- # and redirecting.
- def out_of_bounds?
- current_page > total_pages
- end
-
- # Current offset of the paginated collection. If we're on the first page,
- # it is always 0. If we're on the 2nd page and there are 30 entries per page,
- # the offset is 30. This property is useful if you want to render ordinals
- # side by side with records in the view: simply start with offset + 1.
- def offset
- (current_page - 1) * per_page
- end
-
- # current_page - 1 or nil if there is no previous page
- def previous_page
- current_page > 1 ? (current_page - 1) : nil
- end
-
- # current_page + 1 or nil if there is no next page
- def next_page
- current_page < total_pages ? (current_page + 1) : nil
- end
-
- # sets the total_entries property and calculates total_pages
- def total_entries=(number)
- @total_entries = number.to_i
- @total_pages = (@total_entries / per_page.to_f).ceil
- end
-
- # This is a magic wrapper for the original Array#replace method. It serves
- # for populating the paginated collection after initialization.
- #
- # Why magic? Because it tries to guess the total number of entries judging
- # by the size of given array. If it is shorter than +per_page+ limit, then we
- # know we're on the last page. This trick is very useful for avoiding
- # unnecessary hits to the database to do the counting after we fetched the
- # data for the current page.
- #
- # However, after using +replace+ you should always test the value of
- # +total_entries+ and set it to a proper value if it's +nil+. See the example
- # in +create+.
- def replace(array)
- result = super
-
- # The collection is shorter then page limit? Rejoice, because
- # then we know that we are on the last page!
- if total_entries.nil? and length < per_page and (current_page == 1 or length > 0)
- self.total_entries = offset + length
- end
-
- result
- end
- end
-end
diff --git a/vendor/plugins/will_paginate/lib/will_paginate/core_ext.rb b/vendor/plugins/will_paginate/lib/will_paginate/core_ext.rb
deleted file mode 100644
index 32f10f50..00000000
--- a/vendor/plugins/will_paginate/lib/will_paginate/core_ext.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-require 'set'
-require 'will_paginate/array'
-
-unless Hash.instance_methods.include? 'except'
- Hash.class_eval do
- # Returns a new hash without the given keys.
- def except(*keys)
- rejected = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
- reject { |key,| rejected.include?(key) }
- end
-
- # Replaces the hash without only the given keys.
- def except!(*keys)
- replace(except(*keys))
- end
- end
-end
-
-unless Hash.instance_methods.include? 'slice'
- Hash.class_eval do
- # Returns a new hash with only the given keys.
- def slice(*keys)
- allowed = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
- reject { |key,| !allowed.include?(key) }
- end
-
- # Replaces the hash with only the given keys.
- def slice!(*keys)
- replace(slice(*keys))
- end
- end
-end
diff --git a/vendor/plugins/will_paginate/lib/will_paginate/finder.rb b/vendor/plugins/will_paginate/lib/will_paginate/finder.rb
deleted file mode 100644
index 852bd5d9..00000000
--- a/vendor/plugins/will_paginate/lib/will_paginate/finder.rb
+++ /dev/null
@@ -1,247 +0,0 @@
-require 'will_paginate/core_ext'
-
-module WillPaginate
- # A mixin for ActiveRecord::Base. Provides +per_page+ class method
- # and hooks things up to provide paginating finders.
- #
- # Find out more in WillPaginate::Finder::ClassMethods
- #
- module Finder
- def self.included(base)
- base.extend ClassMethods
- class << base
- alias_method_chain :method_missing, :paginate
- # alias_method_chain :find_every, :paginate
- define_method(:per_page) { 30 } unless respond_to?(:per_page)
- end
- end
-
- # = Paginating finders for ActiveRecord models
- #
- # WillPaginate adds +paginate+, +per_page+ and other methods to
- # ActiveRecord::Base class methods and associations. It also hooks into
- # +method_missing+ to intercept pagination calls to dynamic finders such as
- # +paginate_by_user_id+ and translate them to ordinary finders
- # (+find_all_by_user_id+ in this case).
- #
- # In short, paginating finders are equivalent to ActiveRecord finders; the
- # only difference is that we start with "paginate" instead of "find" and
- # that :page is required parameter:
- #
- # @posts = Post.paginate :all, :page => params[:page], :order => 'created_at DESC'
- #
- # In paginating finders, "all" is implicit. There is no sense in paginating
- # a single record, right? So, you can drop the :all argument:
- #
- # Post.paginate(...) => Post.find :all
- # Post.paginate_all_by_something => Post.find_all_by_something
- # Post.paginate_by_something => Post.find_all_by_something
- #
- # == The importance of the :order parameter
- #
- # In ActiveRecord finders, :order parameter specifies columns for
- # the ORDER BY clause in SQL. It is important to have it, since
- # pagination only makes sense with ordered sets. Without the ORDER
- # BY clause, databases aren't required to do consistent ordering when
- # performing SELECT queries; this is especially true for
- # PostgreSQL.
- #
- # Therefore, make sure you are doing ordering on a column that makes the
- # most sense in the current context. Make that obvious to the user, also.
- # For perfomance reasons you will also want to add an index to that column.
- module ClassMethods
- # This is the main paginating finder.
- #
- # == Special parameters for paginating finders
- # * :page -- REQUIRED, but defaults to 1 if false or nil
- # * :per_page -- defaults to CurrentModel.per_page (which is 30 if not overridden)
- # * :total_entries -- use only if you manually count total entries
- # * :count -- additional options that are passed on to +count+
- # * :finder -- name of the ActiveRecord finder used (default: "find")
- #
- # All other options (+conditions+, +order+, ...) are forwarded to +find+
- # and +count+ calls.
- def paginate(*args, &block)
- options = args.pop
- page, per_page, total_entries = wp_parse_options(options)
- finder = (options[:finder] || 'find').to_s
-
- if finder == 'find'
- # an array of IDs may have been given:
- total_entries ||= (Array === args.first and args.first.size)
- # :all is implicit
- args.unshift(:all) if args.empty?
- end
-
- WillPaginate::Collection.create(page, per_page, total_entries) do |pager|
- count_options = options.except :page, :per_page, :total_entries, :finder
- find_options = count_options.except(:count).update(:offset => pager.offset, :limit => pager.per_page)
-
- args << find_options
- # @options_from_last_find = nil
- pager.replace send(finder, *args, &block)
-
- # magic counting for user convenience:
- pager.total_entries = wp_count(count_options, args, finder) unless pager.total_entries
- end
- end
-
- # Iterates through all records by loading one page at a time. This is useful
- # for migrations or any other use case where you don't want to load all the
- # records in memory at once.
- #
- # It uses +paginate+ internally; therefore it accepts all of its options.
- # You can specify a starting page with :page (default is 1). Default
- # :order is "id" , override if necessary.
- #
- # See {Faking Cursors in ActiveRecord}[http://weblog.jamisbuck.org/2007/4/6/faking-cursors-in-activerecord]
- # where Jamis Buck describes this and a more efficient way for MySQL.
- def paginated_each(options = {}, &block)
- options = { :order => 'id', :page => 1 }.merge options
- options[:page] = options[:page].to_i
- options[:total_entries] = 0 # skip the individual count queries
- total = 0
-
- begin
- collection = paginate(options)
- total += collection.each(&block).size
- options[:page] += 1
- end until collection.size < collection.per_page
-
- total
- end
-
- # Wraps +find_by_sql+ by simply adding LIMIT and OFFSET to your SQL string
- # based on the params otherwise used by paginating finds: +page+ and
- # +per_page+.
- #
- # Example:
- #
- # @developers = Developer.paginate_by_sql ['select * from developers where salary > ?', 80000],
- # :page => params[:page], :per_page => 3
- #
- # A query for counting rows will automatically be generated if you don't
- # supply :total_entries . If you experience problems with this
- # generated SQL, you might want to perform the count manually in your
- # application.
- #
- def paginate_by_sql(sql, options)
- WillPaginate::Collection.create(*wp_parse_options(options)) do |pager|
- query = sanitize_sql(sql)
- original_query = query.dup
- # add limit, offset
- add_limit! query, :offset => pager.offset, :limit => pager.per_page
- # perfom the find
- pager.replace find_by_sql(query)
-
- unless pager.total_entries
- count_query = original_query.sub /\bORDER\s+BY\s+[\w`,\s]+$/mi, ''
- count_query = "SELECT COUNT(*) FROM (#{count_query})"
-
- unless ['oracle', 'oci'].include?(self.connection.adapter_name.downcase)
- count_query << ' AS count_table'
- end
- # perform the count query
- pager.total_entries = count_by_sql(count_query)
- end
- end
- end
-
- def respond_to?(method, include_priv = false) #:nodoc:
- case method.to_sym
- when :paginate, :paginate_by_sql
- true
- else
- super(method.to_s.sub(/^paginate/, 'find'), include_priv)
- end
- end
-
- protected
-
- def method_missing_with_paginate(method, *args, &block) #:nodoc:
- # did somebody tried to paginate? if not, let them be
- unless method.to_s.index('paginate') == 0
- return method_missing_without_paginate(method, *args, &block)
- end
-
- # paginate finders are really just find_* with limit and offset
- finder = method.to_s.sub('paginate', 'find')
- finder.sub!('find', 'find_all') if finder.index('find_by_') == 0
-
- options = args.pop
- raise ArgumentError, 'parameter hash expected' unless options.respond_to? :symbolize_keys
- options = options.dup
- options[:finder] = finder
- args << options
-
- paginate(*args, &block)
- end
-
- # Does the not-so-trivial job of finding out the total number of entries
- # in the database. It relies on the ActiveRecord +count+ method.
- def wp_count(options, args, finder)
- excludees = [:count, :order, :limit, :offset, :readonly]
- unless options[:select] and options[:select] =~ /^\s*DISTINCT\b/i
- excludees << :select # only exclude the select param if it doesn't begin with DISTINCT
- end
-
- # count expects (almost) the same options as find
- count_options = options.except *excludees
-
- # merge the hash found in :count
- # this allows you to specify :select, :order, or anything else just for the count query
- count_options.update options[:count] if options[:count]
-
- # we may be in a model or an association proxy
- klass = (@owner and @reflection) ? @reflection.klass : self
-
- # forget about includes if they are irrelevant (Rails 2.1)
- if count_options[:include] and
- klass.private_methods.include?('references_eager_loaded_tables?') and
- !klass.send(:references_eager_loaded_tables?, count_options)
- count_options.delete :include
- end
-
- # we may have to scope ...
- counter = Proc.new { count(count_options) }
-
- count = if finder.index('find_') == 0 and klass.respond_to?(scoper = finder.sub('find', 'with'))
- # scope_out adds a 'with_finder' method which acts like with_scope, if it's present
- # then execute the count with the scoping provided by the with_finder
- send(scoper, &counter)
- elsif match = /^find_(all_by|by)_([_a-zA-Z]\w*)$/.match(finder)
- # extract conditions from calls like "paginate_by_foo_and_bar"
- attribute_names = extract_attribute_names_from_match(match)
- conditions = construct_attributes_from_arguments(attribute_names, args)
- with_scope(:find => { :conditions => conditions }, &counter)
- else
- counter.call
- end
-
- count.respond_to?(:length) ? count.length : count
- end
-
- def wp_parse_options(options) #:nodoc:
- raise ArgumentError, 'parameter hash expected' unless options.respond_to? :symbolize_keys
- options = options.symbolize_keys
- raise ArgumentError, ':page parameter required' unless options.key? :page
-
- if options[:count] and options[:total_entries]
- raise ArgumentError, ':count and :total_entries are mutually exclusive'
- end
-
- page = options[:page] || 1
- per_page = options[:per_page] || self.per_page
- total = options[:total_entries]
- [page, per_page, total]
- end
-
- private
-
- # def find_every_with_paginate(options)
- # @options_from_last_find = options
- # find_every_without_paginate(options)
- # end
- end
- end
-end
diff --git a/vendor/plugins/will_paginate/lib/will_paginate/named_scope.rb b/vendor/plugins/will_paginate/lib/will_paginate/named_scope.rb
deleted file mode 100644
index 6f00cf76..00000000
--- a/vendor/plugins/will_paginate/lib/will_paginate/named_scope.rb
+++ /dev/null
@@ -1,132 +0,0 @@
-## stolen from: http://dev.rubyonrails.org/browser/trunk/activerecord/lib/active_record/named_scope.rb?rev=9084
-
-module WillPaginate
- # This is a feature backported from Rails 2.1 because of its usefullness not only with will_paginate,
- # but in other aspects when managing complex conditions that you want to be reusable.
- module NamedScope
- # All subclasses of ActiveRecord::Base have two named_scopes:
- # * all , which is similar to a find(:all) query, and
- # * scoped , which allows for the creation of anonymous scopes, on the fly:
- #
- # Shirt.scoped(:conditions => {:color => 'red'}).scoped(:include => :washing_instructions)
- #
- # These anonymous scopes tend to be useful when procedurally generating complex queries, where passing
- # intermediate values (scopes) around as first-class objects is convenient.
- def self.included(base)
- base.class_eval do
- extend ClassMethods
- named_scope :all
- named_scope :scoped, lambda { |scope| scope }
- end
- end
-
- module ClassMethods
- def scopes #:nodoc:
- read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {})
- end
-
- # Adds a class method for retrieving and querying objects. A scope represents a narrowing of a database query,
- # such as :conditions => {:color => :red}, :select => 'shirts.*', :include => :washing_instructions .
- #
- # class Shirt < ActiveRecord::Base
- # named_scope :red, :conditions => {:color => 'red'}
- # named_scope :dry_clean_only, :joins => :washing_instructions, :conditions => ['washing_instructions.dry_clean_only = ?', true]
- # end
- #
- # The above calls to named_scope define class methods Shirt.red and Shirt.dry_clean_only . Shirt.red ,
- # in effect, represents the query Shirt.find(:all, :conditions => {:color => 'red'}) .
- #
- # Unlike Shirt.find(...), however, the object returned by Shirt.red is not an Array; it resembles the association object
- # constructed by a has_many declaration. For instance, you can invoke Shirt.red.find(:first) , Shirt.red.count ,
- # Shirt.red.find(:all, :conditions => {:size => 'small'}) . Also, just
- # as with the association objects, name scopes acts like an Array, implementing Enumerable; Shirt.red.each(&block) ,
- # Shirt.red.first , and Shirt.red.inject(memo, &block) all behave as if Shirt.red really were an Array.
- #
- # These named scopes are composable. For instance, Shirt.red.dry_clean_only will produce all shirts that are both red and dry clean only.
- # Nested finds and calculations also work with these compositions: Shirt.red.dry_clean_only.count returns the number of garments
- # for which these criteria obtain. Similarly with Shirt.red.dry_clean_only.average(:thread_count) .
- #
- # All scopes are available as class methods on the ActiveRecord descendent upon which the scopes were defined. But they are also available to
- # has_many associations. If,
- #
- # class Person < ActiveRecord::Base
- # has_many :shirts
- # end
- #
- # then elton.shirts.red.dry_clean_only will return all of Elton's red, dry clean
- # only shirts.
- #
- # Named scopes can also be procedural.
- #
- # class Shirt < ActiveRecord::Base
- # named_scope :colored, lambda { |color|
- # { :conditions => { :color => color } }
- # }
- # end
- #
- # In this example, Shirt.colored('puce') finds all puce shirts.
- #
- # Named scopes can also have extensions, just as with has_many declarations:
- #
- # class Shirt < ActiveRecord::Base
- # named_scope :red, :conditions => {:color => 'red'} do
- # def dom_id
- # 'red_shirts'
- # end
- # end
- # end
- #
- def named_scope(name, options = {}, &block)
- scopes[name] = lambda do |parent_scope, *args|
- Scope.new(parent_scope, case options
- when Hash
- options
- when Proc
- options.call(*args)
- end, &block)
- end
- (class << self; self end).instance_eval do
- define_method name do |*args|
- scopes[name].call(self, *args)
- end
- end
- end
- end
-
- class Scope #:nodoc:
- attr_reader :proxy_scope, :proxy_options
- [].methods.each { |m| delegate m, :to => :proxy_found unless m =~ /(^__|^nil\?|^send|class|extend|find|count|sum|average|maximum|minimum|paginate)/ }
- delegate :scopes, :with_scope, :to => :proxy_scope
-
- def initialize(proxy_scope, options, &block)
- [options[:extend]].flatten.each { |extension| extend extension } if options[:extend]
- extend Module.new(&block) if block_given?
- @proxy_scope, @proxy_options = proxy_scope, options.except(:extend)
- end
-
- def reload
- load_found; self
- end
-
- protected
- def proxy_found
- @found || load_found
- end
-
- private
- def method_missing(method, *args, &block)
- if scopes.include?(method)
- scopes[method].call(self, *args)
- else
- with_scope :find => proxy_options do
- proxy_scope.send(method, *args, &block)
- end
- end
- end
-
- def load_found
- @found = find(:all)
- end
- end
- end
-end
diff --git a/vendor/plugins/will_paginate/lib/will_paginate/named_scope_patch.rb b/vendor/plugins/will_paginate/lib/will_paginate/named_scope_patch.rb
deleted file mode 100644
index bdc1997f..00000000
--- a/vendor/plugins/will_paginate/lib/will_paginate/named_scope_patch.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-## based on http://dev.rubyonrails.org/changeset/9084
-
-ActiveRecord::Associations::AssociationProxy.class_eval do
- protected
- def with_scope(*args, &block)
- @reflection.klass.send :with_scope, *args, &block
- end
-end
-
-[ ActiveRecord::Associations::AssociationCollection,
- ActiveRecord::Associations::HasManyThroughAssociation ].each do |klass|
- klass.class_eval do
- protected
- alias :method_missing_without_scopes :method_missing_without_paginate
- def method_missing_without_paginate(method, *args, &block)
- if @reflection.klass.scopes.include?(method)
- @reflection.klass.scopes[method].call(self, *args, &block)
- else
- method_missing_without_scopes(method, *args, &block)
- end
- end
- end
-end
-
-# Rails 1.2.6
-ActiveRecord::Associations::HasAndBelongsToManyAssociation.class_eval do
- protected
- def method_missing(method, *args, &block)
- if @target.respond_to?(method) || (!@reflection.klass.respond_to?(method) && Class.respond_to?(method))
- super
- elsif @reflection.klass.scopes.include?(method)
- @reflection.klass.scopes[method].call(self, *args)
- else
- @reflection.klass.with_scope(:find => { :conditions => @finder_sql, :joins => @join_sql, :readonly => false }) do
- @reflection.klass.send(method, *args, &block)
- end
- end
- end
-end if ActiveRecord::Base.respond_to? :find_first
diff --git a/vendor/plugins/will_paginate/lib/will_paginate/version.rb b/vendor/plugins/will_paginate/lib/will_paginate/version.rb
deleted file mode 100644
index 6bcd90d6..00000000
--- a/vendor/plugins/will_paginate/lib/will_paginate/version.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-module WillPaginate
- module VERSION
- MAJOR = 2
- MINOR = 3
- TINY = 3
-
- STRING = [MAJOR, MINOR, TINY].join('.')
- end
-end
diff --git a/vendor/plugins/will_paginate/lib/will_paginate/view_helpers.rb b/vendor/plugins/will_paginate/lib/will_paginate/view_helpers.rb
deleted file mode 100644
index c7060164..00000000
--- a/vendor/plugins/will_paginate/lib/will_paginate/view_helpers.rb
+++ /dev/null
@@ -1,393 +0,0 @@
-require 'will_paginate/core_ext'
-
-module WillPaginate
- # = Will Paginate view helpers
- #
- # The main view helper, #will_paginate, renders
- # pagination links for the given collection. The helper itself is lightweight
- # and serves only as a wrapper around LinkRenderer instantiation; the
- # renderer then does all the hard work of generating the HTML.
- #
- # == Global options for helpers
- #
- # Options for pagination helpers are optional and get their default values from the
- # WillPaginate::ViewHelpers.pagination_options hash. You can write to this hash to
- # override default options on the global level:
- #
- # WillPaginate::ViewHelpers.pagination_options[:previous_label] = 'Previous page'
- #
- # By putting this into "config/initializers/will_paginate.rb" (or simply environment.rb in
- # older versions of Rails) you can easily translate link texts to previous
- # and next pages, as well as override some other defaults to your liking.
- module ViewHelpers
- # default options that can be overridden on the global level
- @@pagination_options = {
- :class => 'pagination',
- :previous_label => '« Previous',
- :next_label => 'Next »',
- :inner_window => 4, # links around the current page
- :outer_window => 1, # links around beginning and end
- :separator => ' ', # single space is friendly to spiders and non-graphic browsers
- :param_name => :page,
- :params => nil,
- :renderer => 'WillPaginate::LinkRenderer',
- :page_links => true,
- :container => true,
- # bennis hack for ajax-support
- :remote => false,
- :update => nil,
- }
- mattr_reader :pagination_options
-
- # Renders Digg/Flickr-style pagination for a WillPaginate::Collection
- # object. Nil is returned if there is only one page in total; no point in
- # rendering the pagination in that case...
- #
- # ==== Options
- # Display options:
- # * :previous_label -- default: "« Previous"
- # * :next_label -- default: "Next »"
- # * :page_links -- when false, only previous/next links are rendered (default: true)
- # * :inner_window -- how many links are shown around the current page (default: 4)
- # * :outer_window -- how many links are around the first and the last page (default: 1)
- # * :separator -- string separator for page HTML elements (default: single space)
- #
- # HTML options:
- # * :class -- CSS class name for the generated DIV (default: "pagination")
- # * :container -- toggles rendering of the DIV container for pagination links, set to
- # false only when you are rendering your own pagination markup (default: true)
- # * :id -- HTML ID for the container (default: nil). Pass +true+ to have the ID
- # automatically generated from the class name of objects in collection: for example, paginating
- # ArticleComment models would yield an ID of "article_comments_pagination".
- #
- # Advanced options:
- # * :param_name -- parameter name for page number in URLs (default: :page )
- # * :params -- additional parameters when generating pagination links
- # (eg. :controller => "foo", :action => nil )
- # * :renderer -- class name, class or instance of a link renderer (default:
- # WillPaginate::LinkRenderer )
- #
- # All options not recognized by will_paginate will become HTML attributes on the container
- # element for pagination links (the DIV). For example:
- #
- # <%= will_paginate @posts, :style => 'font-size: small' %>
- #
- # ... will result in:
- #
- #
- #
- # ==== Using the helper without arguments
- # If the helper is called without passing in the collection object, it will
- # try to read from the instance variable inferred by the controller name.
- # For example, calling +will_paginate+ while the current controller is
- # PostsController will result in trying to read from the @posts
- # variable. Example:
- #
- # <%= will_paginate :id => true %>
- #
- # ... will result in @post collection getting paginated:
- #
- #
- #
- def will_paginate(collection = nil, options = {})
- options, collection = collection, nil if collection.is_a? Hash
- unless collection or !controller
- collection_name = "@#{controller.controller_name}"
- collection = instance_variable_get(collection_name)
- raise ArgumentError, "The #{collection_name} variable appears to be empty. Did you " +
- "forget to pass the collection object for will_paginate?" unless collection
- end
- # early exit if there is nothing to render
- return nil unless WillPaginate::ViewHelpers.total_pages_for_collection(collection) > 1
-
- options = options.symbolize_keys.reverse_merge WillPaginate::ViewHelpers.pagination_options
- if options[:prev_label]
- WillPaginate::Deprecation::warn(":prev_label view parameter is now :previous_label; the old name has been deprecated.")
- options[:previous_label] = options.delete(:prev_label)
- end
-
- # get the renderer instance
- renderer = case options[:renderer]
- when String
- options[:renderer].to_s.constantize.new
- when Class
- options[:renderer].new
- else
- options[:renderer]
- end
- # render HTML for pagination
- renderer.prepare collection, options, self
- renderer.to_html
- end
-
- # Wrapper for rendering pagination links at both top and bottom of a block
- # of content.
- #
- # <% paginated_section @posts do %>
- #
- # <% for post in @posts %>
- # ...
- # <% end %>
- #
- # <% end %>
- #
- # will result in:
- #
- #
- #
- # ...
- #
- #
- #
- # Arguments are passed to a will_paginate call, so the same options
- # apply. Don't use the :id option; otherwise you'll finish with two
- # blocks of pagination links sharing the same ID (which is invalid HTML).
- def paginated_section(*args, &block)
- pagination = will_paginate(*args).to_s
- content = pagination + capture(&block) + pagination
- concat content, block.binding
- end
-
- # Renders a helpful message with numbers of displayed vs. total entries.
- # You can use this as a blueprint for your own, similar helpers.
- #
- # <%= page_entries_info @posts %>
- # #-> Displaying posts 6 - 10 of 26 in total
- #
- # By default, the message will use the humanized class name of objects
- # in collection: for instance, "project types" for ProjectType models.
- # Override this with the :entry_name parameter:
- #
- # <%= page_entries_info @posts, :entry_name => 'item' %>
- # #-> Displaying items 6 - 10 of 26 in total
- def page_entries_info(collection, options = {})
- entry_name = options[:entry_name] ||
- (collection.empty?? 'entry' : collection.first.class.name.underscore.sub('_', ' '))
-
- if collection.total_pages < 2
- case collection.size
- when 0; "No #{entry_name.pluralize} found"
- when 1; "Displaying 1 #{entry_name}"
- else; "Displaying all #{collection.size} #{entry_name.pluralize}"
- end
- else
- %{Displaying #{entry_name.pluralize} %d - %d of %d in total} % [
- collection.offset + 1,
- collection.offset + collection.length,
- collection.total_entries
- ]
- end
- end
-
- def self.total_pages_for_collection(collection) #:nodoc:
- if collection.respond_to?('page_count') and !collection.respond_to?('total_pages')
- WillPaginate::Deprecation.warn <<-MSG
- You are using a paginated collection of class #{collection.class.name}
- which conforms to the old API of WillPaginate::Collection by using
- `page_count`, while the current method name is `total_pages`. Please
- upgrade yours or 3rd-party code that provides the paginated collection.
- MSG
- class << collection
- def total_pages; page_count; end
- end
- end
- collection.total_pages
- end
- end
-
- # This class does the heavy lifting of actually building the pagination
- # links. It is used by the will_paginate helper internally.
- class LinkRenderer
-
- # The gap in page links is represented by:
- #
- # …
- attr_accessor :gap_marker
-
- def initialize
- @gap_marker = '… '
- end
-
- # * +collection+ is a WillPaginate::Collection instance or any other object
- # that conforms to that API
- # * +options+ are forwarded from +will_paginate+ view helper
- # * +template+ is the reference to the template being rendered
- def prepare(collection, options, template)
- @collection = collection
- @options = options
- @template = template
-
- # reset values in case we're re-using this instance
- @total_pages = @param_name = @url_string = nil
- end
-
- # Process it! This method returns the complete HTML string which contains
- # pagination links. Feel free to subclass LinkRenderer and change this
- # method as you see fit.
- def to_html
- links = @options[:page_links] ? windowed_links : []
- # previous/next buttons
- links.unshift page_link_or_span(@collection.previous_page, 'disabled prev_page', @options[:previous_label])
- links.push page_link_or_span(@collection.next_page, 'disabled next_page', @options[:next_label])
-
- html = links.join(@options[:separator])
- @options[:container] ? @template.content_tag(:div, html, html_attributes) : html
- end
-
- # Returns the subset of +options+ this instance was initialized with that
- # represent HTML attributes for the container element of pagination links.
- def html_attributes
- return @html_attributes if @html_attributes
- @html_attributes = @options.except *(WillPaginate::ViewHelpers.pagination_options.keys - [:class])
- # pagination of Post models will have the ID of "posts_pagination"
- if @options[:container] and @options[:id] === true
- @html_attributes[:id] = @collection.first.class.name.underscore.pluralize + '_pagination'
- end
- @html_attributes
- end
-
- protected
-
- # Collects link items for visible page numbers.
- def windowed_links
- prev = nil
-
- visible_page_numbers.inject [] do |links, n|
- # detect gaps:
- links << gap_marker if prev and n > prev + 1
- links << page_link_or_span(n, 'current')
- prev = n
- links
- end
- end
-
- # Calculates visible page numbers using the :inner_window and
- # :outer_window options.
- def visible_page_numbers
- inner_window, outer_window = @options[:inner_window].to_i, @options[:outer_window].to_i
- window_from = current_page - inner_window
- window_to = current_page + inner_window
-
- # adjust lower or upper limit if other is out of bounds
- if window_to > total_pages
- window_from -= window_to - total_pages
- window_to = total_pages
- end
- if window_from < 1
- window_to += 1 - window_from
- window_from = 1
- window_to = total_pages if window_to > total_pages
- end
-
- visible = (1..total_pages).to_a
- left_gap = (2 + outer_window)...window_from
- right_gap = (window_to + 1)...(total_pages - outer_window)
- visible -= left_gap.to_a if left_gap.last - left_gap.first > 1
- visible -= right_gap.to_a if right_gap.last - right_gap.first > 1
-
- visible
- end
-
- def page_link_or_span(page, span_class, text = nil)
- text ||= page.to_s
-
- if page and page != current_page
- classnames = span_class && span_class.index(' ') && span_class.split(' ', 2).last
- page_link page, text, :rel => rel_value(page), :class => classnames
- else
- page_span page, text, :class => span_class
- end
- end
-
- def page_link(page, text, attributes = {})
- # bennis hack to support ajax-support
- if @options[:remote] == true
- @template.link_to_remote text, :url => url_for(page), :html => attributes,
- :before => "Element.show('loader')", :success => "Element.hide('loader')",
- :method => :get, :update => @options[:update]
- else
- @template.link_to text, url_for(page), attributes
- end
- end
-
- def page_span(page, text, attributes = {})
- @template.content_tag :span, text, attributes
- end
-
- # Returns URL params for +page_link_or_span+, taking the current GET params
- # and :params option into account.
- def url_for(page)
- page_one = page == 1
- unless @url_string and !page_one
- @url_params = {}
- # page links should preserve GET parameters
- stringified_merge @url_params, @template.params if @template.request.get?
- stringified_merge @url_params, @options[:params] if @options[:params]
-
- if complex = param_name.index(/[^\w-]/)
- page_param = (defined?(CGIMethods) ? CGIMethods : ActionController::AbstractRequest).
- parse_query_parameters("#{param_name}=#{page}")
-
- stringified_merge @url_params, page_param
- else
- @url_params[param_name] = page_one ? 1 : 2
- end
-
- url = @template.url_for(@url_params)
- return url if page_one
-
- if complex
- @url_string = url.sub(%r!((?:\?|&)#{CGI.escape param_name}=)#{page}!, '\1@')
- return url
- else
- @url_string = url
- @url_params[param_name] = 3
- @template.url_for(@url_params).split(//).each_with_index do |char, i|
- if char == '3' and url[i, 1] == '2'
- @url_string[i] = '@'
- break
- end
- end
- end
- end
- # finally!
- @url_string.sub '@', page.to_s
- end
-
- private
-
- def rel_value(page)
- case page
- when @collection.previous_page; 'prev' + (page == 1 ? ' start' : '')
- when @collection.next_page; 'next'
- when 1; 'start'
- end
- end
-
- def current_page
- @collection.current_page
- end
-
- def total_pages
- @total_pages ||= WillPaginate::ViewHelpers.total_pages_for_collection(@collection)
- end
-
- def param_name
- @param_name ||= @options[:param_name].to_s
- end
-
- # Recursively merge into target hash by using stringified keys from the other one
- def stringified_merge(target, other)
- other.each do |key, value|
- key = key.to_s # this line is what it's all about!
- existing = target[key]
-
- if value.is_a?(Hash) and (existing.is_a?(Hash) or existing.nil?)
- stringified_merge(existing || (target[key] = {}), value)
- else
- target[key] = value
- end
- end
- end
- end
-end
diff --git a/vendor/plugins/will_paginate/test/boot.rb b/vendor/plugins/will_paginate/test/boot.rb
deleted file mode 100644
index 622fc93c..00000000
--- a/vendor/plugins/will_paginate/test/boot.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-plugin_root = File.join(File.dirname(__FILE__), '..')
-version = ENV['RAILS_VERSION']
-version = nil if version and version == ""
-
-# first look for a symlink to a copy of the framework
-if !version and framework_root = ["#{plugin_root}/rails", "#{plugin_root}/../../rails"].find { |p| File.directory? p }
- puts "found framework root: #{framework_root}"
- # this allows for a plugin to be tested outside of an app and without Rails gems
- $:.unshift "#{framework_root}/activesupport/lib", "#{framework_root}/activerecord/lib", "#{framework_root}/actionpack/lib"
-else
- # simply use installed gems if available
- puts "using Rails#{version ? ' ' + version : nil} gems"
- require 'rubygems'
-
- if version
- gem 'rails', version
- else
- gem 'actionpack'
- gem 'activerecord'
- end
-end
diff --git a/vendor/plugins/will_paginate/test/collection_test.rb b/vendor/plugins/will_paginate/test/collection_test.rb
deleted file mode 100644
index b3360901..00000000
--- a/vendor/plugins/will_paginate/test/collection_test.rb
+++ /dev/null
@@ -1,140 +0,0 @@
-require 'helper'
-require 'will_paginate/array'
-
-class ArrayPaginationTest < Test::Unit::TestCase
- def test_simple
- collection = ('a'..'e').to_a
-
- [{ :page => 1, :per_page => 3, :expected => %w( a b c ) },
- { :page => 2, :per_page => 3, :expected => %w( d e ) },
- { :page => 1, :per_page => 5, :expected => %w( a b c d e ) },
- { :page => 3, :per_page => 5, :expected => [] },
- ].
- each do |conditions|
- expected = conditions.delete :expected
- assert_equal expected, collection.paginate(conditions)
- end
- end
-
- def test_defaults
- result = (1..50).to_a.paginate
- assert_equal 1, result.current_page
- assert_equal 30, result.size
- end
-
- def test_deprecated_api
- assert_raise(ArgumentError) { [].paginate(2) }
- assert_raise(ArgumentError) { [].paginate(2, 10) }
- end
-
- def test_total_entries_has_precedence
- result = %w(a b c).paginate :total_entries => 5
- assert_equal 5, result.total_entries
- end
-
- def test_argument_error_with_params_and_another_argument
- assert_raise ArgumentError do
- [].paginate({}, 5)
- end
- end
-
- def test_paginated_collection
- entries = %w(a b c)
- collection = create(2, 3, 10) do |pager|
- assert_equal entries, pager.replace(entries)
- end
-
- assert_equal entries, collection
- assert_respond_to_all collection, %w(total_pages each offset size current_page per_page total_entries)
- assert_kind_of Array, collection
- assert_instance_of Array, collection.entries
- assert_equal 3, collection.offset
- assert_equal 4, collection.total_pages
- assert !collection.out_of_bounds?
- end
-
- def test_previous_next_pages
- collection = create(1, 1, 3)
- assert_nil collection.previous_page
- assert_equal 2, collection.next_page
-
- collection = create(2, 1, 3)
- assert_equal 1, collection.previous_page
- assert_equal 3, collection.next_page
-
- collection = create(3, 1, 3)
- assert_equal 2, collection.previous_page
- assert_nil collection.next_page
- end
-
- def test_out_of_bounds
- entries = create(2, 3, 2){}
- assert entries.out_of_bounds?
-
- entries = create(1, 3, 2){}
- assert !entries.out_of_bounds?
- end
-
- def test_guessing_total_count
- entries = create do |pager|
- # collection is shorter than limit
- pager.replace array
- end
- assert_equal 8, entries.total_entries
-
- entries = create(2, 5, 10) do |pager|
- # collection is shorter than limit, but we have an explicit count
- pager.replace array
- end
- assert_equal 10, entries.total_entries
-
- entries = create do |pager|
- # collection is the same as limit; we can't guess
- pager.replace array(5)
- end
- assert_equal nil, entries.total_entries
-
- entries = create do |pager|
- # collection is empty; we can't guess
- pager.replace array(0)
- end
- assert_equal nil, entries.total_entries
-
- entries = create(1) do |pager|
- # collection is empty and we're on page 1,
- # so the whole thing must be empty, too
- pager.replace array(0)
- end
- assert_equal 0, entries.total_entries
- end
-
- def test_invalid_page
- bad_inputs = [0, -1, nil, '', 'Schnitzel']
-
- bad_inputs.each do |bad|
- assert_raise(WillPaginate::InvalidPage) { create bad }
- end
- end
-
- def test_invalid_per_page_setting
- assert_raise(ArgumentError) { create(1, -1) }
- end
-
- def test_page_count_was_removed
- assert_raise(NoMethodError) { create.page_count }
- # It's `total_pages` now.
- end
-
- private
- def create(page = 2, limit = 5, total = nil, &block)
- if block_given?
- WillPaginate::Collection.create(page, limit, total, &block)
- else
- WillPaginate::Collection.new(page, limit, total)
- end
- end
-
- def array(size = 3)
- Array.new(size)
- end
-end
diff --git a/vendor/plugins/will_paginate/test/console b/vendor/plugins/will_paginate/test/console
deleted file mode 100755
index 3f282f11..00000000
--- a/vendor/plugins/will_paginate/test/console
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/usr/bin/env ruby
-irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
-libs = []
-
-libs << 'irb/completion'
-libs << File.join('lib', 'load_fixtures')
-
-exec "#{irb} -Ilib:test#{libs.map{ |l| " -r #{l}" }.join} --simple-prompt"
diff --git a/vendor/plugins/will_paginate/test/database.yml b/vendor/plugins/will_paginate/test/database.yml
deleted file mode 100644
index 28c54307..00000000
--- a/vendor/plugins/will_paginate/test/database.yml
+++ /dev/null
@@ -1,22 +0,0 @@
-sqlite3:
- database: ":memory:"
- adapter: sqlite3
- timeout: 500
-
-sqlite2:
- database: ":memory:"
- adapter: sqlite2
-
-mysql:
- adapter: mysql
- username: root
- password:
- encoding: utf8
- database: will_paginate_unittest
-
-postgres:
- adapter: postgresql
- username: mislav
- password: mislav
- database: will_paginate_unittest
- min_messages: warning
diff --git a/vendor/plugins/will_paginate/test/finder_test.rb b/vendor/plugins/will_paginate/test/finder_test.rb
deleted file mode 100644
index 001cf3a7..00000000
--- a/vendor/plugins/will_paginate/test/finder_test.rb
+++ /dev/null
@@ -1,434 +0,0 @@
-require 'helper'
-require 'lib/activerecord_test_case'
-
-require 'will_paginate'
-WillPaginate.enable_activerecord
-WillPaginate.enable_named_scope
-
-class FinderTest < ActiveRecordTestCase
- fixtures :topics, :replies, :users, :projects, :developers_projects
-
- def test_new_methods_presence
- assert_respond_to_all Topic, %w(per_page paginate paginate_by_sql)
- end
-
- def test_simple_paginate
- assert_queries(1) do
- entries = Topic.paginate :page => nil
- assert_equal 1, entries.current_page
- assert_equal 1, entries.total_pages
- assert_equal 4, entries.size
- end
-
- assert_queries(2) do
- entries = Topic.paginate :page => 2
- assert_equal 1, entries.total_pages
- assert entries.empty?
- end
- end
-
- def test_parameter_api
- # :page parameter in options is required!
- assert_raise(ArgumentError){ Topic.paginate }
- assert_raise(ArgumentError){ Topic.paginate({}) }
-
- # explicit :all should not break anything
- assert_equal Topic.paginate(:page => nil), Topic.paginate(:all, :page => 1)
-
- # :count could be nil and we should still not cry
- assert_nothing_raised { Topic.paginate :page => 1, :count => nil }
- end
-
- def test_paginate_with_per_page
- entries = Topic.paginate :page => 1, :per_page => 1
- assert_equal 1, entries.size
- assert_equal 4, entries.total_pages
-
- # Developer class has explicit per_page at 10
- entries = Developer.paginate :page => 1
- assert_equal 10, entries.size
- assert_equal 2, entries.total_pages
-
- entries = Developer.paginate :page => 1, :per_page => 5
- assert_equal 11, entries.total_entries
- assert_equal 5, entries.size
- assert_equal 3, entries.total_pages
- end
-
- def test_paginate_with_order
- entries = Topic.paginate :page => 1, :order => 'created_at desc'
- expected = [topics(:futurama), topics(:harvey_birdman), topics(:rails), topics(:ar)].reverse
- assert_equal expected, entries.to_a
- assert_equal 1, entries.total_pages
- end
-
- def test_paginate_with_conditions
- entries = Topic.paginate :page => 1, :conditions => ["created_at > ?", 30.minutes.ago]
- expected = [topics(:rails), topics(:ar)]
- assert_equal expected, entries.to_a
- assert_equal 1, entries.total_pages
- end
-
- def test_paginate_with_include_and_conditions
- entries = Topic.paginate \
- :page => 1,
- :include => :replies,
- :conditions => "replies.content LIKE 'Bird%' ",
- :per_page => 10
-
- expected = Topic.find :all,
- :include => 'replies',
- :conditions => "replies.content LIKE 'Bird%' ",
- :limit => 10
-
- assert_equal expected, entries.to_a
- assert_equal 1, entries.total_entries
- end
-
- def test_paginate_with_include_and_order
- entries = nil
- assert_queries(2) do
- entries = Topic.paginate \
- :page => 1,
- :include => :replies,
- :order => 'replies.created_at asc, topics.created_at asc',
- :per_page => 10
- end
-
- expected = Topic.find :all,
- :include => 'replies',
- :order => 'replies.created_at asc, topics.created_at asc',
- :limit => 10
-
- assert_equal expected, entries.to_a
- assert_equal 4, entries.total_entries
- end
-
- def test_paginate_associations_with_include
- entries, project = nil, projects(:active_record)
-
- assert_nothing_raised "THIS IS A BUG in Rails 1.2.3 that was fixed in [7326]. " +
- "Please upgrade to a newer version of Rails." do
- entries = project.topics.paginate \
- :page => 1,
- :include => :replies,
- :conditions => "replies.content LIKE 'Nice%' ",
- :per_page => 10
- end
-
- expected = Topic.find :all,
- :include => 'replies',
- :conditions => "project_id = #{project.id} AND replies.content LIKE 'Nice%' ",
- :limit => 10
-
- assert_equal expected, entries.to_a
- end
-
- def test_paginate_associations
- dhh = users :david
- expected_name_ordered = [projects(:action_controller), projects(:active_record)]
- expected_id_ordered = [projects(:active_record), projects(:action_controller)]
-
- assert_queries(2) do
- # with association-specified order
- entries = dhh.projects.paginate(:page => 1)
- assert_equal expected_name_ordered, entries
- assert_equal 2, entries.total_entries
- end
-
- # with explicit order
- entries = dhh.projects.paginate(:page => 1, :order => 'projects.id')
- assert_equal expected_id_ordered, entries
- assert_equal 2, entries.total_entries
-
- assert_nothing_raised { dhh.projects.find(:all, :order => 'projects.id', :limit => 4) }
- entries = dhh.projects.paginate(:page => 1, :order => 'projects.id', :per_page => 4)
- assert_equal expected_id_ordered, entries
-
- # has_many with implicit order
- topic = Topic.find(1)
- expected = [replies(:spam), replies(:witty_retort)]
- assert_equal expected.map(&:id).sort, topic.replies.paginate(:page => 1).map(&:id).sort
- assert_equal expected.reverse, topic.replies.paginate(:page => 1, :order => 'replies.id ASC')
- end
-
- def test_paginate_association_extension
- project = Project.find(:first)
-
- assert_queries(2) do
- entries = project.replies.paginate_recent :page => 1
- assert_equal [replies(:brave)], entries
- end
- end
-
- def test_paginate_with_joins
- entries = nil
-
- assert_queries(1) do
- entries = Developer.paginate :page => 1,
- :joins => 'LEFT JOIN developers_projects ON users.id = developers_projects.developer_id',
- :conditions => 'project_id = 1'
- assert_equal 2, entries.size
- developer_names = entries.map &:name
- assert developer_names.include?('David')
- assert developer_names.include?('Jamis')
- end
-
- assert_queries(1) do
- expected = entries.to_a
- entries = Developer.paginate :page => 1,
- :joins => 'LEFT JOIN developers_projects ON users.id = developers_projects.developer_id',
- :conditions => 'project_id = 1', :count => { :select => "users.id" }
- assert_equal expected, entries.to_a
- assert_equal 2, entries.total_entries
- end
- end
-
- def test_paginate_with_group
- entries = nil
- assert_queries(1) do
- entries = Developer.paginate :page => 1, :per_page => 10,
- :group => 'salary', :select => 'salary', :order => 'salary'
- end
-
- expected = [ users(:david), users(:jamis), users(:dev_10), users(:poor_jamis) ].map(&:salary).sort
- assert_equal expected, entries.map(&:salary)
- end
-
- def test_paginate_with_dynamic_finder
- expected = [replies(:witty_retort), replies(:spam)]
- assert_equal expected, Reply.paginate_by_topic_id(1, :page => 1)
-
- entries = Developer.paginate :conditions => { :salary => 100000 }, :page => 1, :per_page => 5
- assert_equal 8, entries.total_entries
- assert_equal entries, Developer.paginate_by_salary(100000, :page => 1, :per_page => 5)
-
- # dynamic finder + conditions
- entries = Developer.paginate_by_salary(100000, :page => 1,
- :conditions => ['id > ?', 6])
- assert_equal 4, entries.total_entries
- assert_equal (7..10).to_a, entries.map(&:id)
-
- assert_raises NoMethodError do
- Developer.paginate_by_inexistent_attribute 100000, :page => 1
- end
- end
-
- def test_scoped_paginate
- entries = Developer.with_poor_ones { Developer.paginate :page => 1 }
-
- assert_equal 2, entries.size
- assert_equal 2, entries.total_entries
- end
-
- ## named_scope ##
-
- def test_paginate_in_named_scope
- entries = Developer.poor.paginate :page => 1, :per_page => 1
-
- assert_equal 1, entries.size
- assert_equal 2, entries.total_entries
- end
-
- def test_paginate_in_named_scope_on_habtm_association
- project = projects(:active_record)
- assert_queries(2) do
- entries = project.developers.poor.paginate :page => 1, :per_page => 1
-
- assert_equal 1, entries.size, 'one developer should be found'
- assert_equal 1, entries.total_entries, 'only one developer should be found'
- end
- end
-
- def test_paginate_in_named_scope_on_hmt_association
- project = projects(:active_record)
- expected = [replies(:brave)]
-
- assert_queries(2) do
- entries = project.replies.recent.paginate :page => 1, :per_page => 1
- assert_equal expected, entries
- assert_equal 1, entries.total_entries, 'only one reply should be found'
- end
- end
-
- def test_paginate_in_named_scope_on_has_many_association
- project = projects(:active_record)
- expected = [topics(:ar)]
-
- assert_queries(2) do
- entries = project.topics.mentions_activerecord.paginate :page => 1, :per_page => 1
- assert_equal expected, entries
- assert_equal 1, entries.total_entries, 'only one topic should be found'
- end
- end
-
- ## misc ##
-
- def test_count_and_total_entries_options_are_mutually_exclusive
- e = assert_raise ArgumentError do
- Developer.paginate :page => 1, :count => {}, :total_entries => 1
- end
- assert_match /exclusive/, e.to_s
- end
-
- def test_readonly
- assert_nothing_raised { Developer.paginate :readonly => true, :page => 1 }
- end
-
- # this functionality is temporarily removed
- def xtest_pagination_defines_method
- pager = "paginate_by_created_at"
- assert !User.methods.include?(pager), "User methods should not include `#{pager}` method"
- # paginate!
- assert 0, User.send(pager, nil, :page => 1).total_entries
- # the paging finder should now be defined
- assert User.methods.include?(pager), "`#{pager}` method should be defined on User"
- end
-
- # Is this Rails 2.0? Find out by testing find_all which was removed in [6998]
- unless ActiveRecord::Base.respond_to? :find_all
- def test_paginate_array_of_ids
- # AR finders also accept arrays of IDs
- # (this was broken in Rails before [6912])
- assert_queries(1) do
- entries = Developer.paginate((1..8).to_a, :per_page => 3, :page => 2, :order => 'id')
- assert_equal (4..6).to_a, entries.map(&:id)
- assert_equal 8, entries.total_entries
- end
- end
- end
-
- uses_mocha 'internals' do
- def test_implicit_all_with_dynamic_finders
- Topic.expects(:find_all_by_foo).returns([])
- Topic.expects(:count).returns(0)
- Topic.paginate_by_foo :page => 2
- end
-
- def test_guessing_the_total_count
- Topic.expects(:find).returns(Array.new(2))
- Topic.expects(:count).never
-
- entries = Topic.paginate :page => 2, :per_page => 4
- assert_equal 6, entries.total_entries
- end
-
- def test_guessing_that_there_are_no_records
- Topic.expects(:find).returns([])
- Topic.expects(:count).never
-
- entries = Topic.paginate :page => 1, :per_page => 4
- assert_equal 0, entries.total_entries
- end
-
- def test_extra_parameters_stay_untouched
- Topic.expects(:find).with(:all, {:foo => 'bar', :limit => 4, :offset => 0 }).returns(Array.new(5))
- Topic.expects(:count).with({:foo => 'bar'}).returns(1)
-
- Topic.paginate :foo => 'bar', :page => 1, :per_page => 4
- end
-
- def test_count_skips_select
- Developer.stubs(:find).returns([])
- Developer.expects(:count).with({}).returns(0)
- Developer.paginate :select => 'salary', :page => 2
- end
-
- def test_count_select_when_distinct
- Developer.stubs(:find).returns([])
- Developer.expects(:count).with(:select => 'DISTINCT salary').returns(0)
- Developer.paginate :select => 'DISTINCT salary', :page => 2
- end
-
- def test_should_use_scoped_finders_if_present
- # scope-out compatibility
- Topic.expects(:find_best).returns(Array.new(5))
- Topic.expects(:with_best).returns(1)
-
- Topic.paginate_best :page => 1, :per_page => 4
- end
-
- def test_paginate_by_sql
- assert_respond_to Developer, :paginate_by_sql
- Developer.expects(:find_by_sql).with(regexp_matches(/sql LIMIT 3(,| OFFSET) 3/)).returns([])
- Developer.expects(:count_by_sql).with('SELECT COUNT(*) FROM (sql) AS count_table').returns(0)
-
- entries = Developer.paginate_by_sql 'sql', :page => 2, :per_page => 3
- end
-
- def test_paginate_by_sql_respects_total_entries_setting
- Developer.expects(:find_by_sql).returns([])
- Developer.expects(:count_by_sql).never
-
- entries = Developer.paginate_by_sql 'sql', :page => 1, :total_entries => 999
- assert_equal 999, entries.total_entries
- end
-
- def test_paginate_by_sql_strips_order_by_when_counting
- Developer.expects(:find_by_sql).returns([])
- Developer.expects(:count_by_sql).with("SELECT COUNT(*) FROM (sql\n ) AS count_table").returns(0)
-
- Developer.paginate_by_sql "sql\n ORDER\nby foo, bar, `baz` ASC", :page => 2
- end
-
- # TODO: counts are still wrong
- def test_ability_to_use_with_custom_finders
- # acts_as_taggable defines find_tagged_with(tag, options)
- Topic.expects(:find_tagged_with).with('will_paginate', :offset => 5, :limit => 5).returns([])
- Topic.expects(:count).with({}).returns(0)
-
- Topic.paginate_tagged_with 'will_paginate', :page => 2, :per_page => 5
- end
-
- def test_array_argument_doesnt_eliminate_count
- ids = (1..8).to_a
- Developer.expects(:find_all_by_id).returns([])
- Developer.expects(:count).returns(0)
-
- Developer.paginate_by_id(ids, :per_page => 3, :page => 2, :order => 'id')
- end
-
- def test_paginating_finder_doesnt_mangle_options
- Developer.expects(:find).returns([])
- options = { :page => 1 }
- options.expects(:delete).never
- options_before = options.dup
-
- Developer.paginate(options)
- assert_equal options, options_before
- end
-
- def test_paginated_each
- collection = stub('collection', :size => 5, :empty? => false, :per_page => 5)
- collection.expects(:each).times(2).returns(collection)
- last_collection = stub('collection', :size => 4, :empty? => false, :per_page => 5)
- last_collection.expects(:each).returns(last_collection)
-
- params = { :order => 'id', :total_entries => 0 }
-
- Developer.expects(:paginate).with(params.merge(:page => 2)).returns(collection)
- Developer.expects(:paginate).with(params.merge(:page => 3)).returns(collection)
- Developer.expects(:paginate).with(params.merge(:page => 4)).returns(last_collection)
-
- assert_equal 14, Developer.paginated_each(:page => '2') { }
- end
-
- # detect ActiveRecord 2.1
- if ActiveRecord::Base.private_methods.include?('references_eager_loaded_tables?')
- def test_removes_irrelevant_includes_in_count
- Developer.expects(:find).returns([1])
- Developer.expects(:count).with({}).returns(0)
-
- Developer.paginate :page => 1, :per_page => 1, :include => :projects
- end
-
- def test_doesnt_remove_referenced_includes_in_count
- Developer.expects(:find).returns([1])
- Developer.expects(:count).with({ :include => :projects, :conditions => 'projects.id > 2' }).returns(0)
-
- Developer.paginate :page => 1, :per_page => 1,
- :include => :projects, :conditions => 'projects.id > 2'
- end
- end
- end
-end
diff --git a/vendor/plugins/will_paginate/test/fixtures/admin.rb b/vendor/plugins/will_paginate/test/fixtures/admin.rb
deleted file mode 100644
index 1d5e7f36..00000000
--- a/vendor/plugins/will_paginate/test/fixtures/admin.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-class Admin < User
- has_many :companies, :finder_sql => 'SELECT * FROM companies'
-end
diff --git a/vendor/plugins/will_paginate/test/fixtures/developer.rb b/vendor/plugins/will_paginate/test/fixtures/developer.rb
deleted file mode 100644
index 7105355d..00000000
--- a/vendor/plugins/will_paginate/test/fixtures/developer.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-class Developer < User
- has_and_belongs_to_many :projects, :include => :topics, :order => 'projects.name'
-
- def self.with_poor_ones(&block)
- with_scope :find => { :conditions => ['salary <= ?', 80000], :order => 'salary' } do
- yield
- end
- end
-
- named_scope :poor, :conditions => ['salary <= ?', 80000], :order => 'salary'
-
- def self.per_page() 10 end
-end
diff --git a/vendor/plugins/will_paginate/test/fixtures/developers_projects.yml b/vendor/plugins/will_paginate/test/fixtures/developers_projects.yml
deleted file mode 100644
index cee359c7..00000000
--- a/vendor/plugins/will_paginate/test/fixtures/developers_projects.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-david_action_controller:
- developer_id: 1
- project_id: 2
- joined_on: 2004-10-10
-
-david_active_record:
- developer_id: 1
- project_id: 1
- joined_on: 2004-10-10
-
-jamis_active_record:
- developer_id: 2
- project_id: 1
\ No newline at end of file
diff --git a/vendor/plugins/will_paginate/test/fixtures/project.rb b/vendor/plugins/will_paginate/test/fixtures/project.rb
deleted file mode 100644
index 0f85ef5e..00000000
--- a/vendor/plugins/will_paginate/test/fixtures/project.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class Project < ActiveRecord::Base
- has_and_belongs_to_many :developers, :uniq => true
-
- has_many :topics
- # :finder_sql => 'SELECT * FROM topics WHERE (topics.project_id = #{id})',
- # :counter_sql => 'SELECT COUNT(*) FROM topics WHERE (topics.project_id = #{id})'
-
- has_many :replies, :through => :topics do
- def find_recent(params = {})
- with_scope :find => { :conditions => ['replies.created_at > ?', 15.minutes.ago] } do
- find :all, params
- end
- end
- end
-end
diff --git a/vendor/plugins/will_paginate/test/fixtures/projects.yml b/vendor/plugins/will_paginate/test/fixtures/projects.yml
deleted file mode 100644
index 74f3c32f..00000000
--- a/vendor/plugins/will_paginate/test/fixtures/projects.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-active_record:
- id: 1
- name: Active Record
-action_controller:
- id: 2
- name: Active Controller
diff --git a/vendor/plugins/will_paginate/test/fixtures/replies.yml b/vendor/plugins/will_paginate/test/fixtures/replies.yml
deleted file mode 100644
index 9a83c004..00000000
--- a/vendor/plugins/will_paginate/test/fixtures/replies.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-witty_retort:
- id: 1
- topic_id: 1
- content: Birdman is better!
- created_at: <%= 6.hours.ago.to_s(:db) %>
-
-another:
- id: 2
- topic_id: 2
- content: Nuh uh!
- created_at: <%= 1.hour.ago.to_s(:db) %>
-
-spam:
- id: 3
- topic_id: 1
- content: Nice site!
- created_at: <%= 1.hour.ago.to_s(:db) %>
-
-decisive:
- id: 4
- topic_id: 4
- content: "I'm getting to the bottom of this"
- created_at: <%= 30.minutes.ago.to_s(:db) %>
-
-brave:
- id: 5
- topic_id: 4
- content: "AR doesn't scare me a bit"
- created_at: <%= 10.minutes.ago.to_s(:db) %>
diff --git a/vendor/plugins/will_paginate/test/fixtures/reply.rb b/vendor/plugins/will_paginate/test/fixtures/reply.rb
deleted file mode 100644
index ecaf3c1f..00000000
--- a/vendor/plugins/will_paginate/test/fixtures/reply.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-class Reply < ActiveRecord::Base
- belongs_to :topic, :include => [:replies]
-
- named_scope :recent, :conditions => ['replies.created_at > ?', 15.minutes.ago]
-
- validates_presence_of :content
-end
diff --git a/vendor/plugins/will_paginate/test/fixtures/schema.rb b/vendor/plugins/will_paginate/test/fixtures/schema.rb
deleted file mode 100644
index 8831aad2..00000000
--- a/vendor/plugins/will_paginate/test/fixtures/schema.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-ActiveRecord::Schema.define do
-
- create_table "users", :force => true do |t|
- t.column "name", :text
- t.column "salary", :integer, :default => 70000
- t.column "created_at", :datetime
- t.column "updated_at", :datetime
- t.column "type", :text
- end
-
- create_table "projects", :force => true do |t|
- t.column "name", :text
- end
-
- create_table "developers_projects", :id => false, :force => true do |t|
- t.column "developer_id", :integer, :null => false
- t.column "project_id", :integer, :null => false
- t.column "joined_on", :date
- t.column "access_level", :integer, :default => 1
- end
-
- create_table "topics", :force => true do |t|
- t.column "project_id", :integer
- t.column "title", :string
- t.column "subtitle", :string
- t.column "content", :text
- t.column "created_at", :datetime
- t.column "updated_at", :datetime
- end
-
- create_table "replies", :force => true do |t|
- t.column "content", :text
- t.column "created_at", :datetime
- t.column "updated_at", :datetime
- t.column "topic_id", :integer
- end
-
-end
diff --git a/vendor/plugins/will_paginate/test/fixtures/topic.rb b/vendor/plugins/will_paginate/test/fixtures/topic.rb
deleted file mode 100644
index 77be0dda..00000000
--- a/vendor/plugins/will_paginate/test/fixtures/topic.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-class Topic < ActiveRecord::Base
- has_many :replies, :dependent => :destroy, :order => 'replies.created_at DESC'
- belongs_to :project
-
- named_scope :mentions_activerecord, :conditions => ['topics.title LIKE ?', '%ActiveRecord%']
-end
diff --git a/vendor/plugins/will_paginate/test/fixtures/topics.yml b/vendor/plugins/will_paginate/test/fixtures/topics.yml
deleted file mode 100644
index 0a269047..00000000
--- a/vendor/plugins/will_paginate/test/fixtures/topics.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-futurama:
- id: 1
- title: Isnt futurama awesome?
- subtitle: It really is, isnt it.
- content: I like futurama
- created_at: <%= 1.day.ago.to_s(:db) %>
- updated_at:
-
-harvey_birdman:
- id: 2
- title: Harvey Birdman is the king of all men
- subtitle: yup
- content: He really is
- created_at: <%= 2.hours.ago.to_s(:db) %>
- updated_at:
-
-rails:
- id: 3
- project_id: 1
- title: Rails is nice
- subtitle: It makes me happy
- content: except when I have to hack internals to fix pagination. even then really.
- created_at: <%= 20.minutes.ago.to_s(:db) %>
-
-ar:
- id: 4
- project_id: 1
- title: ActiveRecord sometimes freaks me out
- content: "I mean, what's the deal with eager loading?"
- created_at: <%= 15.minutes.ago.to_s(:db) %>
diff --git a/vendor/plugins/will_paginate/test/fixtures/user.rb b/vendor/plugins/will_paginate/test/fixtures/user.rb
deleted file mode 100644
index 4a57cf07..00000000
--- a/vendor/plugins/will_paginate/test/fixtures/user.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-class User < ActiveRecord::Base
-end
diff --git a/vendor/plugins/will_paginate/test/fixtures/users.yml b/vendor/plugins/will_paginate/test/fixtures/users.yml
deleted file mode 100644
index ed2c03ae..00000000
--- a/vendor/plugins/will_paginate/test/fixtures/users.yml
+++ /dev/null
@@ -1,35 +0,0 @@
-david:
- id: 1
- name: David
- salary: 80000
- type: Developer
-
-jamis:
- id: 2
- name: Jamis
- salary: 150000
- type: Developer
-
-<% for digit in 3..10 %>
-dev_<%= digit %>:
- id: <%= digit %>
- name: fixture_<%= digit %>
- salary: 100000
- type: Developer
-<% end %>
-
-poor_jamis:
- id: 11
- name: Jamis
- salary: 9000
- type: Developer
-
-admin:
- id: 12
- name: admin
- type: Admin
-
-goofy:
- id: 13
- name: Goofy
- type: Admin
diff --git a/vendor/plugins/will_paginate/test/helper.rb b/vendor/plugins/will_paginate/test/helper.rb
deleted file mode 100644
index ad52b1b6..00000000
--- a/vendor/plugins/will_paginate/test/helper.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-require 'test/unit'
-require 'rubygems'
-
-# gem install redgreen for colored test output
-begin require 'redgreen'; rescue LoadError; end
-
-require 'boot' unless defined?(ActiveRecord)
-
-class Test::Unit::TestCase
- protected
- def assert_respond_to_all object, methods
- methods.each do |method|
- [method.to_s, method.to_sym].each { |m| assert_respond_to object, m }
- end
- end
-
- def collect_deprecations
- old_behavior = WillPaginate::Deprecation.behavior
- deprecations = []
- WillPaginate::Deprecation.behavior = Proc.new do |message, callstack|
- deprecations << message
- end
- result = yield
- [result, deprecations]
- ensure
- WillPaginate::Deprecation.behavior = old_behavior
- end
-end
-
-# Wrap tests that use Mocha and skip if unavailable.
-def uses_mocha(test_name)
- require 'mocha' unless Object.const_defined?(:Mocha)
-rescue LoadError => load_error
- $stderr.puts "Skipping #{test_name} tests. `gem install mocha` and try again."
-else
- yield
-end
diff --git a/vendor/plugins/will_paginate/test/lib/activerecord_test_case.rb b/vendor/plugins/will_paginate/test/lib/activerecord_test_case.rb
deleted file mode 100644
index 8f66ebee..00000000
--- a/vendor/plugins/will_paginate/test/lib/activerecord_test_case.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-require 'lib/activerecord_test_connector'
-
-class ActiveRecordTestCase < Test::Unit::TestCase
- # Set our fixture path
- if ActiveRecordTestConnector.able_to_connect
- self.fixture_path = File.join(File.dirname(__FILE__), '..', 'fixtures')
- self.use_transactional_fixtures = true
- end
-
- def self.fixtures(*args)
- super if ActiveRecordTestConnector.connected
- end
-
- def run(*args)
- super if ActiveRecordTestConnector.connected
- end
-
- # Default so Test::Unit::TestCase doesn't complain
- def test_truth
- end
-
- protected
-
- def assert_queries(num = 1)
- $query_count = 0
- yield
- ensure
- assert_equal num, $query_count, "#{$query_count} instead of #{num} queries were executed."
- end
-
- def assert_no_queries(&block)
- assert_queries(0, &block)
- end
-end
-
-ActiveRecordTestConnector.setup
diff --git a/vendor/plugins/will_paginate/test/lib/activerecord_test_connector.rb b/vendor/plugins/will_paginate/test/lib/activerecord_test_connector.rb
deleted file mode 100644
index 0decd8a2..00000000
--- a/vendor/plugins/will_paginate/test/lib/activerecord_test_connector.rb
+++ /dev/null
@@ -1,69 +0,0 @@
-require 'active_record'
-require 'active_record/version'
-require 'active_record/fixtures'
-
-class ActiveRecordTestConnector
- cattr_accessor :able_to_connect
- cattr_accessor :connected
-
- FIXTURES_PATH = File.join(File.dirname(__FILE__), '..', 'fixtures')
-
- # Set our defaults
- self.connected = false
- self.able_to_connect = true
-
- def self.setup
- unless self.connected || !self.able_to_connect
- setup_connection
- load_schema
- Dependencies.load_paths.unshift FIXTURES_PATH
- self.connected = true
- end
- rescue Exception => e # errors from ActiveRecord setup
- $stderr.puts "\nSkipping ActiveRecord tests: #{e}"
- $stderr.puts "Install SQLite3 to run the full test suite for will_paginate.\n\n"
- self.able_to_connect = false
- end
-
- private
-
- def self.setup_connection
- db = ENV['DB'].blank?? 'sqlite3' : ENV['DB']
-
- configurations = YAML.load_file(File.join(File.dirname(__FILE__), '..', 'database.yml'))
- raise "no configuration for '#{db}'" unless configurations.key? db
- configuration = configurations[db]
-
- ActiveRecord::Base.logger = Logger.new(STDOUT) if $0 == 'irb'
- puts "using #{configuration['adapter']} adapter" unless ENV['DB'].blank?
-
- ActiveRecord::Base.establish_connection(configuration)
- ActiveRecord::Base.configurations = { db => configuration }
- prepare ActiveRecord::Base.connection
-
- unless Object.const_defined?(:QUOTED_TYPE)
- Object.send :const_set, :QUOTED_TYPE, ActiveRecord::Base.connection.quote_column_name('type')
- end
- end
-
- def self.load_schema
- ActiveRecord::Base.silence do
- ActiveRecord::Migration.verbose = false
- load File.join(FIXTURES_PATH, 'schema.rb')
- end
- end
-
- def self.prepare(conn)
- class << conn
- IGNORED_SQL = [/^PRAGMA/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/, /^SHOW FIELDS /]
-
- def execute_with_counting(sql, name = nil, &block)
- $query_count ||= 0
- $query_count += 1 unless IGNORED_SQL.any? { |r| sql =~ r }
- execute_without_counting(sql, name, &block)
- end
-
- alias_method_chain :execute, :counting
- end
- end
-end
diff --git a/vendor/plugins/will_paginate/test/lib/load_fixtures.rb b/vendor/plugins/will_paginate/test/lib/load_fixtures.rb
deleted file mode 100644
index 10d6f420..00000000
--- a/vendor/plugins/will_paginate/test/lib/load_fixtures.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require 'boot'
-require 'lib/activerecord_test_connector'
-
-# setup the connection
-ActiveRecordTestConnector.setup
-
-# load all fixtures
-Fixtures.create_fixtures(ActiveRecordTestConnector::FIXTURES_PATH, ActiveRecord::Base.connection.tables)
-
-require 'will_paginate'
-WillPaginate.enable_activerecord
diff --git a/vendor/plugins/will_paginate/test/lib/view_test_process.rb b/vendor/plugins/will_paginate/test/lib/view_test_process.rb
deleted file mode 100644
index e4e79d57..00000000
--- a/vendor/plugins/will_paginate/test/lib/view_test_process.rb
+++ /dev/null
@@ -1,165 +0,0 @@
-require 'action_controller'
-require 'action_controller/test_process'
-
-require 'will_paginate'
-WillPaginate.enable_actionpack
-
-ActionController::Routing::Routes.draw do |map|
- map.connect 'dummy/page/:page', :controller => 'dummy'
- map.connect 'dummy/dots/page.:page', :controller => 'dummy', :action => 'dots'
- map.connect 'ibocorp/:page', :controller => 'ibocorp',
- :requirements => { :page => /\d+/ },
- :defaults => { :page => 1 }
-
- map.connect ':controller/:action/:id'
-end
-
-ActionController::Base.perform_caching = false
-
-class WillPaginate::ViewTestCase < Test::Unit::TestCase
- def setup
- super
- @controller = DummyController.new
- @request = @controller.request
- @html_result = nil
- @template = '<%= will_paginate collection, options %>'
-
- @view = ActionView::Base.new
- @view.assigns['controller'] = @controller
- @view.assigns['_request'] = @request
- @view.assigns['_params'] = @request.params
- end
-
- def test_no_complain; end
-
- protected
-
- def paginate(collection = {}, options = {}, &block)
- if collection.instance_of? Hash
- page_options = { :page => 1, :total_entries => 11, :per_page => 4 }.merge(collection)
- collection = [1].paginate(page_options)
- end
-
- locals = { :collection => collection, :options => options }
-
- if defined? ActionView::InlineTemplate
- # Rails 2.1
- args = [ ActionView::InlineTemplate.new(@view, @template, locals) ]
- else
- # older Rails versions
- args = [nil, @template, nil, locals]
- end
-
- @html_result = @view.render_template(*args)
- @html_document = HTML::Document.new(@html_result, true, false)
-
- if block_given?
- classname = options[:class] || WillPaginate::ViewHelpers.pagination_options[:class]
- assert_select("div.#{classname}", 1, 'no main DIV', &block)
- end
- end
-
- def response_from_page_or_rjs
- @html_document.root
- end
-
- def validate_page_numbers expected, links, param_name = :page
- param_pattern = /\W#{CGI.escape(param_name.to_s)}=([^&]*)/
-
- assert_equal(expected, links.map { |e|
- e['href'] =~ param_pattern
- $1 ? $1.to_i : $1
- })
- end
-
- def assert_links_match pattern, links = nil, numbers = nil
- links ||= assert_select 'div.pagination a[href]' do |elements|
- elements
- end
-
- pages = [] if numbers
-
- links.each do |el|
- assert_match pattern, el['href']
- if numbers
- el['href'] =~ pattern
- pages << ($1.nil?? nil : $1.to_i)
- end
- end
-
- assert_equal numbers, pages, "page numbers don't match" if numbers
- end
-
- def assert_no_links_match pattern
- assert_select 'div.pagination a[href]' do |elements|
- elements.each do |el|
- assert_no_match pattern, el['href']
- end
- end
- end
-end
-
-class DummyRequest
- attr_accessor :symbolized_path_parameters
-
- def initialize
- @get = true
- @params = {}
- @symbolized_path_parameters = { :controller => 'foo', :action => 'bar' }
- end
-
- def get?
- @get
- end
-
- def post
- @get = false
- end
-
- def relative_url_root
- ''
- end
-
- def params(more = nil)
- @params.update(more) if more
- @params
- end
-end
-
-class DummyController
- attr_reader :request
- attr_accessor :controller_name
-
- def initialize
- @request = DummyRequest.new
- @url = ActionController::UrlRewriter.new(@request, @request.params)
- end
-
- def params
- @request.params
- end
-
- def url_for(params)
- @url.rewrite(params)
- end
-end
-
-module HTML
- Node.class_eval do
- def inner_text
- children.map(&:inner_text).join('')
- end
- end
-
- Text.class_eval do
- def inner_text
- self.to_s
- end
- end
-
- Tag.class_eval do
- def inner_text
- childless?? '' : super
- end
- end
-end
diff --git a/vendor/plugins/will_paginate/test/tasks.rake b/vendor/plugins/will_paginate/test/tasks.rake
deleted file mode 100644
index 05804813..00000000
--- a/vendor/plugins/will_paginate/test/tasks.rake
+++ /dev/null
@@ -1,59 +0,0 @@
-require 'rake/testtask'
-
-desc 'Test the will_paginate plugin.'
-Rake::TestTask.new(:test) do |t|
- t.pattern = 'test/**/*_test.rb'
- t.verbose = true
- t.libs << 'test'
-end
-
-# I want to specify environment variables at call time
-class EnvTestTask < Rake::TestTask
- attr_accessor :env
-
- def ruby(*args)
- env.each { |key, value| ENV[key] = value } if env
- super
- env.keys.each { |key| ENV.delete key } if env
- end
-end
-
-for configuration in %w( sqlite3 mysql postgres )
- EnvTestTask.new("test_#{configuration}") do |t|
- t.pattern = 'test/finder_test.rb'
- t.verbose = true
- t.env = { 'DB' => configuration }
- t.libs << 'test'
- end
-end
-
-task :test_databases => %w(test_mysql test_sqlite3 test_postgres)
-
-desc %{Test everything on SQLite3, MySQL and PostgreSQL}
-task :test_full => %w(test test_mysql test_postgres)
-
-desc %{Test everything with Rails 2.1.x, 2.0.x & 1.2.x gems}
-task :test_all do
- all = Rake::Task['test_full']
- versions = %w(2.1.0 2.0.2 1.2.6)
- versions.each do |version|
- ENV['RAILS_VERSION'] = "~> #{version}"
- all.invoke
- reset_invoked unless version == versions.last
- end
-end
-
-def reset_invoked
- %w( test_full test test_mysql test_postgres ).each do |name|
- Rake::Task[name].instance_variable_set '@already_invoked', false
- end
-end
-
-task :rcov do
- excludes = %w( lib/will_paginate/named_scope*
- lib/will_paginate/core_ext.rb
- lib/will_paginate.rb
- rails* )
-
- system %[rcov -Itest:lib test/*.rb -x #{excludes.join(',')}]
-end
diff --git a/vendor/plugins/will_paginate/test/view_test.rb b/vendor/plugins/will_paginate/test/view_test.rb
deleted file mode 100644
index bd6b77f8..00000000
--- a/vendor/plugins/will_paginate/test/view_test.rb
+++ /dev/null
@@ -1,363 +0,0 @@
-require 'helper'
-require 'lib/view_test_process'
-
-class AdditionalLinkAttributesRenderer < WillPaginate::LinkRenderer
- def initialize(link_attributes = nil)
- super()
- @additional_link_attributes = link_attributes || { :default => 'true' }
- end
-
- def page_link(page, text, attributes = {})
- @template.link_to text, url_for(page), attributes.merge(@additional_link_attributes)
- end
-end
-
-class ViewTest < WillPaginate::ViewTestCase
-
- ## basic pagination ##
-
- def test_will_paginate
- paginate do |pagination|
- assert_select 'a[href]', 3 do |elements|
- validate_page_numbers [2,3,2], elements
- assert_select elements.last, ':last-child', "Next »"
- end
- assert_select 'span', 2
- assert_select 'span.disabled:first-child', '« Previous'
- assert_select 'span.current', '1'
- assert_equal '« Previous 1 2 3 Next »', pagination.first.inner_text
- end
- end
-
- def test_no_pagination_when_page_count_is_one
- paginate :per_page => 30
- assert_equal '', @html_result
- end
-
- def test_will_paginate_with_options
- paginate({ :page => 2 },
- :class => 'will_paginate', :previous_label => 'Prev', :next_label => 'Next') do
- assert_select 'a[href]', 4 do |elements|
- validate_page_numbers [1,1,3,3], elements
- # test rel attribute values:
- assert_select elements[1], 'a', '1' do |link|
- assert_equal 'prev start', link.first['rel']
- end
- assert_select elements.first, 'a', "Prev" do |link|
- assert_equal 'prev start', link.first['rel']
- end
- assert_select elements.last, 'a', "Next" do |link|
- assert_equal 'next', link.first['rel']
- end
- end
- assert_select 'span.current', '2'
- end
- end
-
- def test_will_paginate_using_renderer_class
- paginate({}, :renderer => AdditionalLinkAttributesRenderer) do
- assert_select 'a[default=true]', 3
- end
- end
-
- def test_will_paginate_using_renderer_instance
- renderer = WillPaginate::LinkRenderer.new
- renderer.gap_marker = '~~ '
-
- paginate({ :per_page => 2 }, :inner_window => 0, :outer_window => 0, :renderer => renderer) do
- assert_select 'span.my-gap', '~~'
- end
-
- renderer = AdditionalLinkAttributesRenderer.new(:title => 'rendered')
- paginate({}, :renderer => renderer) do
- assert_select 'a[title=rendered]', 3
- end
- end
-
- def test_prev_next_links_have_classnames
- paginate do |pagination|
- assert_select 'span.disabled.prev_page:first-child'
- assert_select 'a.next_page[href]:last-child'
- end
- end
-
- def test_prev_label_deprecated
- assert_deprecated ':previous_label' do
- paginate({ :page => 2 }, :prev_label => 'Deprecated') do
- assert_select 'a[href]:first-child', 'Deprecated'
- end
- end
- end
-
- def test_full_output
- paginate
- expected = <<-HTML
-
- HTML
- expected.strip!.gsub!(/\s{2,}/, ' ')
-
- assert_dom_equal expected, @html_result
- end
-
- def test_escaping_of_urls
- paginate({:page => 1, :per_page => 1, :total_entries => 2},
- :page_links => false, :params => { :tag => ' ' })
-
- assert_select 'a[href]', 1 do |links|
- query = links.first['href'].split('?', 2)[1]
- assert_equal %w(page=2 tag=%3Cbr%3E), query.split('&').sort
- end
- end
-
- ## advanced options for pagination ##
-
- def test_will_paginate_without_container
- paginate({}, :container => false)
- assert_select 'div.pagination', 0, 'main DIV present when it shouldn\'t'
- assert_select 'a[href]', 3
- end
-
- def test_will_paginate_without_page_links
- paginate({ :page => 2 }, :page_links => false) do
- assert_select 'a[href]', 2 do |elements|
- validate_page_numbers [1,3], elements
- end
- end
- end
-
- def test_will_paginate_windows
- paginate({ :page => 6, :per_page => 1 }, :inner_window => 1) do |pagination|
- assert_select 'a[href]', 8 do |elements|
- validate_page_numbers [5,1,2,5,7,10,11,7], elements
- assert_select elements.first, 'a', '« Previous'
- assert_select elements.last, 'a', 'Next »'
- end
- assert_select 'span.current', '6'
- assert_equal '« Previous 1 2 … 5 6 7 … 10 11 Next »', pagination.first.inner_text
- end
- end
-
- def test_will_paginate_eliminates_small_gaps
- paginate({ :page => 6, :per_page => 1 }, :inner_window => 2) do
- assert_select 'a[href]', 12 do |elements|
- validate_page_numbers [5,1,2,3,4,5,7,8,9,10,11,7], elements
- end
- end
- end
-
- def test_container_id
- paginate do |div|
- assert_nil div.first['id']
- end
-
- # magic ID
- paginate({}, :id => true) do |div|
- assert_equal 'fixnums_pagination', div.first['id']
- end
-
- # explicit ID
- paginate({}, :id => 'custom_id') do |div|
- assert_equal 'custom_id', div.first['id']
- end
- end
-
- ## other helpers ##
-
- def test_paginated_section
- @template = <<-ERB
- <% paginated_section collection, options do %>
- <%= content_tag :div, '', :id => "developers" %>
- <% end %>
- ERB
-
- paginate
- assert_select 'div.pagination', 2
- assert_select 'div.pagination + div#developers', 1
- end
-
- def test_page_entries_info
- @template = '<%= page_entries_info collection %>'
- array = ('a'..'z').to_a
-
- paginate array.paginate(:page => 2, :per_page => 5)
- assert_equal %{Displaying strings 6 - 10 of 26 in total},
- @html_result
-
- paginate array.paginate(:page => 7, :per_page => 4)
- assert_equal %{Displaying strings 25 - 26 of 26 in total},
- @html_result
- end
-
- def test_page_entries_info_with_longer_class_name
- @template = '<%= page_entries_info collection %>'
- collection = ('a'..'z').to_a.paginate
- collection.first.stubs(:class).returns(mock('class', :name => 'ProjectType'))
-
- paginate collection
- assert @html_result.index('project types'), "expected <#{@html_result.inspect}> to mention 'project types'"
- end
-
- def test_page_entries_info_with_single_page_collection
- @template = '<%= page_entries_info collection %>'
-
- paginate(('a'..'d').to_a.paginate(:page => 1, :per_page => 5))
- assert_equal %{Displaying all 4 strings}, @html_result
-
- paginate(['a'].paginate(:page => 1, :per_page => 5))
- assert_equal %{Displaying 1 string}, @html_result
-
- paginate([].paginate(:page => 1, :per_page => 5))
- assert_equal %{No entries found}, @html_result
- end
-
- def test_page_entries_info_with_custom_entry_name
- @template = '<%= page_entries_info collection, :entry_name => "author" %>'
-
- entries = (1..20).to_a
-
- paginate(entries.paginate(:page => 1, :per_page => 5))
- assert_equal %{Displaying authors 1 - 5 of 20 in total}, @html_result
-
- paginate(entries.paginate(:page => 1, :per_page => 20))
- assert_equal %{Displaying all 20 authors}, @html_result
-
- paginate(['a'].paginate(:page => 1, :per_page => 5))
- assert_equal %{Displaying 1 author}, @html_result
-
- paginate([].paginate(:page => 1, :per_page => 5))
- assert_equal %{No authors found}, @html_result
- end
-
- ## parameter handling in page links ##
-
- def test_will_paginate_preserves_parameters_on_get
- @request.params :foo => { :bar => 'baz' }
- paginate
- assert_links_match /foo%5Bbar%5D=baz/
- end
-
- def test_will_paginate_doesnt_preserve_parameters_on_post
- @request.post
- @request.params :foo => 'bar'
- paginate
- assert_no_links_match /foo=bar/
- end
-
- def test_adding_additional_parameters
- paginate({}, :params => { :foo => 'bar' })
- assert_links_match /foo=bar/
- end
-
- def test_adding_anchor_parameter
- paginate({}, :params => { :anchor => 'anchor' })
- assert_links_match /#anchor$/
- end
-
- def test_removing_arbitrary_parameters
- @request.params :foo => 'bar'
- paginate({}, :params => { :foo => nil })
- assert_no_links_match /foo=bar/
- end
-
- def test_adding_additional_route_parameters
- paginate({}, :params => { :controller => 'baz', :action => 'list' })
- assert_links_match %r{\Wbaz/list\W}
- end
-
- def test_will_paginate_with_custom_page_param
- paginate({ :page => 2 }, :param_name => :developers_page) do
- assert_select 'a[href]', 4 do |elements|
- validate_page_numbers [1,1,3,3], elements, :developers_page
- end
- end
- end
-
- def test_complex_custom_page_param
- @request.params :developers => { :page => 2 }
-
- paginate({ :page => 2 }, :param_name => 'developers[page]') do
- assert_select 'a[href]', 4 do |links|
- assert_links_match /\?developers%5Bpage%5D=\d+$/, links
- validate_page_numbers [1,1,3,3], links, 'developers[page]'
- end
- end
- end
-
- def test_custom_routing_page_param
- @request.symbolized_path_parameters.update :controller => 'dummy', :action => nil
- paginate :per_page => 2 do
- assert_select 'a[href]', 6 do |links|
- assert_links_match %r{/page/(\d+)$}, links, [2, 3, 4, 5, 6, 2]
- end
- end
- end
-
- def test_custom_routing_page_param_with_dot_separator
- @request.symbolized_path_parameters.update :controller => 'dummy', :action => 'dots'
- paginate :per_page => 2 do
- assert_select 'a[href]', 6 do |links|
- assert_links_match %r{/page\.(\d+)$}, links, [2, 3, 4, 5, 6, 2]
- end
- end
- end
-
- def test_custom_routing_with_first_page_hidden
- @request.symbolized_path_parameters.update :controller => 'ibocorp', :action => nil
- paginate :page => 2, :per_page => 2 do
- assert_select 'a[href]', 7 do |links|
- assert_links_match %r{/ibocorp(?:/(\d+))?$}, links, [nil, nil, 3, 4, 5, 6, 3]
- end
- end
- end
-
- ## internal hardcore stuff ##
-
- class LegacyCollection < WillPaginate::Collection
- alias :page_count :total_pages
- undef :total_pages
- end
-
- def test_deprecation_notices_with_page_count
- collection = LegacyCollection.new(1, 1, 2)
-
- assert_deprecated collection.class.name do
- paginate collection
- end
- end
-
- uses_mocha 'view internals' do
- def test_collection_name_can_be_guessed
- collection = mock
- collection.expects(:total_pages).returns(1)
-
- @template = '<%= will_paginate options %>'
- @controller.controller_name = 'developers'
- @view.assigns['developers'] = collection
-
- paginate(nil)
- end
- end
-
- def test_inferred_collection_name_raises_error_when_nil
- @template = '<%= will_paginate options %>'
- @controller.controller_name = 'developers'
-
- e = assert_raise ArgumentError do
- paginate(nil)
- end
- assert e.message.include?('@developers')
- end
-
- if ActionController::Base.respond_to? :rescue_responses
- # only on Rails 2
- def test_rescue_response_hook_presence
- assert_equal :not_found,
- ActionController::Base.rescue_responses['WillPaginate::InvalidPage']
- end
- end
-
-end
diff --git a/vendor/plugins/will_paginate/will_paginate.gemspec b/vendor/plugins/will_paginate/will_paginate.gemspec
deleted file mode 100644
index 92e00978..00000000
--- a/vendor/plugins/will_paginate/will_paginate.gemspec
+++ /dev/null
@@ -1,21 +0,0 @@
-Gem::Specification.new do |s|
- s.name = 'will_paginate'
- s.version = '2.3.2'
- s.date = '2008-05-16'
-
- s.summary = "Most awesome pagination solution for Rails"
- s.description = "The will_paginate library provides a simple, yet powerful and extensible API for ActiveRecord pagination and rendering of pagination links in ActionView templates."
-
- s.authors = ['Mislav Marohnić', 'PJ Hyett']
- s.email = 'mislav.marohnic@gmail.com'
- s.homepage = 'http://github.com/mislav/will_paginate/wikis'
-
- s.has_rdoc = true
- s.rdoc_options = ['--main', 'README.rdoc']
- s.rdoc_options << '--inline-source' << '--charset=UTF-8'
- s.extra_rdoc_files = ['README.rdoc', 'LICENSE', 'CHANGELOG']
- s.add_dependency 'activesupport', ['>= 1.4.4']
-
- s.files = %w(CHANGELOG LICENSE README.rdoc Rakefile examples examples/apple-circle.gif examples/index.haml examples/index.html examples/pagination.css examples/pagination.sass init.rb lib lib/will_paginate lib/will_paginate.rb lib/will_paginate/array.rb lib/will_paginate/collection.rb lib/will_paginate/core_ext.rb lib/will_paginate/finder.rb lib/will_paginate/named_scope.rb lib/will_paginate/named_scope_patch.rb lib/will_paginate/version.rb lib/will_paginate/view_helpers.rb test test/boot.rb test/collection_test.rb test/console test/database.yml test/finder_test.rb test/fixtures test/fixtures/admin.rb test/fixtures/developer.rb test/fixtures/developers_projects.yml test/fixtures/project.rb test/fixtures/projects.yml test/fixtures/replies.yml test/fixtures/reply.rb test/fixtures/schema.rb test/fixtures/topic.rb test/fixtures/topics.yml test/fixtures/user.rb test/fixtures/users.yml test/helper.rb test/lib test/lib/activerecord_test_case.rb test/lib/activerecord_test_connector.rb test/lib/load_fixtures.rb test/lib/view_test_process.rb test/tasks.rake test/view_test.rb)
- s.test_files = %w(test/boot.rb test/collection_test.rb test/console test/database.yml test/finder_test.rb test/fixtures test/fixtures/admin.rb test/fixtures/developer.rb test/fixtures/developers_projects.yml test/fixtures/project.rb test/fixtures/projects.yml test/fixtures/replies.yml test/fixtures/reply.rb test/fixtures/schema.rb test/fixtures/topic.rb test/fixtures/topics.yml test/fixtures/user.rb test/fixtures/users.yml test/helper.rb test/lib test/lib/activerecord_test_case.rb test/lib/activerecord_test_connector.rb test/lib/load_fixtures.rb test/lib/view_test_process.rb test/tasks.rake test/view_test.rb)
-end