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 -%> - - - - - <% end -%> - -
    <%= User::setting_keys[setting] %><%= @user.settings[setting] == '1' ? 'ja' : 'nein' %>
    -

    - 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 %> - - - - - - - - - -
    NameBeschreibung
    - <%= @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 @@ - - - - - - -<% for article_category in ArticleCategory.find(:all) -%> - 'category') -%>" id="category_<%= article_category.id -%>"> - - - - - -<% end -%> -
    NameBeschreibung
    <%=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?' -%>
    -
    -<%= 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 %> -
    -
    -

    -
    -
    - -

    - - Pflichtfelder sind: Name, Einheit, (netto) Preis und Bestellnummer. - -

    - <% form_tag(update_all_supplier_articles_path(@supplier)) do %> - - - - - - - - - - - - - - - - <% for article in @articles %> - <% fields_for 'articles[]', article do |form| %> - > - - - - - - - - - - - <% end %> - <% end %> - - -
    verf.NameEinheitPreisGebGrBest.Nr.NotizKategorieMwSt.Pfand
    - <%= 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 -%>

    - 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" %> - - - - - - - - - - - - - - - - - - <% for invoice in @invoices %> - - - - - - - - - - - - - <% end %> - -
    NummerLieferantinDatumBezahlt amBetragLieferungBestellungNote
    <%= 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 %>
    - -
    - -<%= 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']}%> -

    - - - - - - - - - - - - - <% @financial_transactions.each do |t| %> - "> - - - - - - <% end %> - -
    > - <%= sort_link_helper "Datum", "date" %> - Wer> - <%= sort_link_helper "Notiz", "note" %> - > - <%= sort_link_helper "Betrag", "amount" %> -
    <%= format_time(t.created_on) %><%=h t.user.nil? ? '??' : t.user.nick %><%=h t.note %><%= number_to_currency(t.amount) %>
    - -<% 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

    -
    -
    - - <%= text_field_tag("query", params['query'], :size => 10 ) %> -
    - <%= 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

    -
    -
    -

    -

    - - <%= text_field_tag("query", params['query'], :size => 10 ) %> -
    -

    - <%= 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 } - ] - } - ] --%> - 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 - foodsoft - %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" %> - - - - - - - - - - - - - - - - - - - - - - - - - <% for ordergroup in @ordergroups %> - - - - - - - - - - - - - - - - - - - - - - - - <% end %> -
    TypeNameDescriptionAccount BalanceAccount UpdatedCreated OnRole AdminRole SuppliersRole Article MetaRole FinanceRole OrdersWeekly TaskWeekdayTask NameTask DescriptionTask Required UsersDeleted AtContact PersonContact PhoneContact Address
    <%=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) %>
    - 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

    -
    -
    - - - - - - - - - - <% if not @order.stockit? -%> - - <% end %> - - - - - <%- - total = 0 - i = 0 - @articles_grouped_by_category.each do |category, order_articles| - -%> - - - - - <%- - 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 - -%> - - - - - - - - <% if not @order.stockit? -%> - - <% end %> - - - - <%- i = i + 1 - end - end -%> - -
    NamePreisEinheitFehlende EinheitenMengeToleranzSumme
    <%=h category %>
    <%= 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})") %> - - " 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 -%> - <%= number_to_currency(article_total, :unit => "") %> € - -
    -
    -
    - <%= 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 %>
    - - - - - <% for setting in User::setting_keys.keys -%> - - - - - <% end -%> -
    Einstellungen:
    <%= check_box_tag "user[setting_attributes][#{setting}]", '1', @user.settings[setting] == '1' || @user.settings_default(setting) %>
    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 = $('
    #{t('ui.marks.close').html_safe}
    '); + +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 = $('
    #{escape_javascript(t('ui.marks.close').html_safe)}
    '); + +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" %> - - - - - - - - - - - - - - - - - - - - - - - - - <% for workgroup in @workgroups %> - - - - - - - - - - - - - - - - - - - - - - - - <% end %> -
    TypeNameDescriptionAccount BalanceAccount UpdatedCreated OnRole AdminRole SuppliersRole Article MetaRole FinanceRole OrdersWeekly TaskWeekdayTask NameTask DescriptionTask Required UsersDeleted AtContact PersonContact PhoneContact Address
    <%=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) %>
    - 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 =~ /^