diff --git a/Gemfile b/Gemfile
index 3be7cf8c..c04e5041 100644
--- a/Gemfile
+++ b/Gemfile
@@ -31,18 +31,20 @@ gem 'client_side_validations'
gem 'client_side_validations-simple_form'
gem 'inherited_resources'
gem 'localize_input', git: "git://github.com/bennibu/localize_input.git"
-gem 'wikicloth'
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 "rails-settings-cached", "0.2.4"
gem 'resque'
gem 'whenever', require: false # For defining cronjobs, see config/schedule.rb
+# we use the git version of acts_as_versioned, and need to include it in this Gemfile
+gem 'acts_as_versioned', git: 'git://github.com/technoweenie/acts_as_versioned.git'
+gem 'foodsoft_wiki', path: 'lib/foodsoft_wiki'
+
group :production do
gem 'exception_notification'
end
@@ -78,10 +80,9 @@ group :test do
gem 'rspec-rails'
gem 'factory_girl_rails', '~> 4.0'
gem 'faker'
- # version requirements to avoid problem http://stackoverflow.com/questions/18114544
- gem 'capybara', '~> 2.1.0'
+ gem 'capybara'
# webkit and poltergeist don't seem to work yet
- gem 'selenium-webdriver', '~> 2.35.1'
+ gem 'selenium-webdriver'
gem 'database_cleaner'
gem 'simplecov', require: false
# need to include rspec components before i18n-spec or rake fails in test environment
diff --git a/Gemfile.lock b/Gemfile.lock
index 4c756a49..9783d484 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -18,6 +18,14 @@ GIT
acts_as_versioned (0.6.0)
activerecord (>= 3.0.9)
+PATH
+ remote: lib/foodsoft_wiki
+ specs:
+ foodsoft_wiki (0.0.1)
+ acts_as_versioned
+ rails (~> 3.2.15)
+ wikicloth
+
GEM
remote: https://rubygems.org/
specs:
@@ -251,7 +259,7 @@ GEM
rspec-mocks (~> 2.14.0)
ruby-prof (0.13.0)
ruby-rc4 (0.1.5)
- rubyzip (0.9.9)
+ rubyzip (1.0.0)
sass (3.2.12)
sass-rails (3.2.6)
railties (~> 3.2.0)
@@ -259,10 +267,10 @@ GEM
tilt (~> 1.3)
select2-rails (3.5.0)
thor (~> 0.14)
- selenium-webdriver (2.35.1)
+ selenium-webdriver (2.37.0)
childprocess (>= 0.2.5)
multi_json (~> 1.0)
- rubyzip (< 1.0.0)
+ rubyzip (~> 1.0.0)
websocket (~> 1.0.4)
simple-navigation (3.11.0)
activesupport (>= 2.3.2)
@@ -308,9 +316,9 @@ GEM
rails (>= 3.1)
railties (>= 3.1)
tzinfo (0.3.38)
- uglifier (2.2.1)
+ uglifier (2.3.0)
execjs (>= 0.3.0)
- multi_json (~> 1.0, >= 1.0.2)
+ json (>= 1.8.0)
uniform_notifier (1.3.0)
vegas (0.1.11)
rack (>= 1.0.0)
@@ -336,7 +344,7 @@ DEPENDENCIES
bullet
capistrano (= 2.13.5)
capistrano-ext
- capybara (~> 2.1.0)
+ capybara
client_side_validations
client_side_validations-simple_form
coffee-rails (~> 3.2.1)
@@ -345,6 +353,7 @@ DEPENDENCIES
exception_notification
factory_girl_rails (~> 4.0)
faker
+ foodsoft_wiki!
haml-rails
i18n-js!
i18n-spec
@@ -369,7 +378,7 @@ DEPENDENCIES
ruby-prof
sass-rails (~> 3.2.3)
select2-rails
- selenium-webdriver (~> 2.35.1)
+ selenium-webdriver
simple-navigation
simple-navigation-bootstrap
simple_form
@@ -380,4 +389,3 @@ DEPENDENCIES
twitter-bootstrap-rails
uglifier (>= 1.0.3)
whenever
- wikicloth
diff --git a/README.md b/README.md
index ffe83101..93d7d740 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,8 @@ FoodSoft
Web-based software to manage a non-profit food coop (product catalog, ordering, accounting, job scheduling).
+A food cooperative is a group of people that buy food from suppliers of their own choosing. A collective do-it-yourself supermarket. Members order their products online and collect them on a specified day. And all put in a bit of work to make that possible. Foodsoft facilitates the process.
+
If you're a food coop considering to use foodsoft, please have a look at the [wiki page for foodcoops](https://github.com/foodcoops/foodsoft/wiki/For-foodcoops). When you'd like to experiment with or develop foodsoft, you can read [how to set it up](https://github.com/foodcoops/foodsoft/blob/master/doc/SETUP_DEVELOPMENT.md) on your own computer.
More information about using this software and contributing can be found on the [wiki](https://github.com/foodcoops/foodsoft/wiki).
diff --git a/app/controllers/group_orders_controller.rb b/app/controllers/group_orders_controller.rb
index 31d1178a..5869d3ff 100644
--- a/app/controllers/group_orders_controller.rb
+++ b/app/controllers/group_orders_controller.rb
@@ -65,7 +65,7 @@ class GroupOrdersController < ApplicationController
private
# Returns true if @current_user is member of an Ordergroup.
- # Used as a :before_filter by OrderingController.
+ # Used as a :before_filter by OrdersController.
def ensure_ordergroup_member
@ordergroup = @current_user.ordergroup
if @ordergroup.nil?
diff --git a/app/controllers/memberships_controller.rb b/app/controllers/memberships_controller.rb
deleted file mode 100644
index e8373675..00000000
--- a/app/controllers/memberships_controller.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-class MembershipsController < ApplicationController
- before_filter :authenticate_membership_or_admin
-
- def add_member
- user = User.find(params[:user_id])
- Membership.create(:group => @group, :user => user)
- redirect_to :action => 'reload', :id => @group
- end
-
- def drop_member
- begin
- Membership.find(params[:membership_id]).destroy
- if User.find(@current_user.id).role_admin?
- redirect_to :action => 'reload', :id => @group
- else
- # If the user drops himself from admin group
- flash[:notice] = MESG_NO_ADMIN_ANYMORE
- render(:update) {|page| page.redirect_to :controller => "index"}
- end
- rescue => error
- flash[:error] = error.to_s
- redirect_to :action => 'reload', :id => @group
- end
- end
-
- def reload
- render :update do |page|
- page.replace_html 'members', :partial => 'shared/memberships/current_members', :object => @group
- page.replace_html 'non_members', :partial => 'shared/memberships/non_members', :object => @group
- end
- end
-
-end
diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb
index d52ae698..578327f1 100644
--- a/app/controllers/orders_controller.rb
+++ b/app/controllers/orders_controller.rb
@@ -48,6 +48,9 @@ class OrdersController < ApplicationController
end
send_data pdf.to_pdf, filename: pdf.filename, type: 'application/pdf'
end
+ format.text do
+ send_data text_fax_template, filename: @order.name+'.txt', type: 'text/plain'
+ end
end
end
@@ -101,12 +104,14 @@ class OrdersController < ApplicationController
rescue => error
redirect_to orders_url, alert: I18n.t('errors.general_msg', :msg => error.message)
end
+
+ protected
# Renders the fax-text-file
# e.g. for easier use with online-fax-software, which don't accept pdf-files
+ # TODO move to text template
def text_fax_template
- order = Order.find(params[:id])
- supplier = order.supplier
+ supplier = @order.supplier
contact = FoodsoftConfig[:contact].symbolize_keys
text = I18n.t('orders.fax.heading', :name => FoodsoftConfig[:name])
text += "\n#{Supplier.human_attribute_name(:customer_number)}: #{supplier.customer_number}" unless supplier.customer_number.blank?
@@ -117,15 +122,13 @@ class OrdersController < ApplicationController
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|
+ @order.order_articles.ordered.all(:include => [:article, :article_price]).each do |oa|
number = oa.article.order_number
(8 - number.size).times { number += " " }
quantity = oa.units_to_order.to_i.to_s
quantity = " " + quantity if quantity.size < 2
text += "#{number} #{quantity} #{oa.article.name}\n"
end
- send_data text,
- :type => 'text/plain; charset=utf-8; header=present',
- :disposition => "attachment; filename=#{order.name}"
+ text
end
end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 43a36fa5..59994432 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -78,14 +78,14 @@ module ApplicationHelper
# When the 'short' option is true, abbreviations will be used:
# When there is a non-empty model attribute 'foo', it looks for
# the model attribute translation 'foo_short' and use that as
- # heading, with an acronym title of 'foo'.
+ # heading, with an abbreviation title of 'foo'.
# Other options are passed through to I18n.
def heading_helper(model, attribute, options = {})
i18nopts = options.select {|a| !['short'].include?(a) }
s = model.human_attribute_name(attribute, i18nopts)
if options[:short]
sshort = model.human_attribute_name("#{attribute}_short".to_sym, options.merge({defaults: ''}))
- s = raw "#{sshort}" unless sshort.empty?
+ s = raw "#{sshort}" unless sshort.empty?
end
s
end
diff --git a/app/models/article.rb b/app/models/article.rb
index a3b4af33..0c809784 100644
--- a/app/models/article.rb
+++ b/app/models/article.rb
@@ -106,7 +106,7 @@ class Article < ActiveRecord::Base
# to get the correspondent shared article
def shared_article
- @shared_article ||= self.supplier.shared_supplier.shared_articles.find_by_number(self.order_number)
+ @shared_article ||= self.supplier.shared_supplier.shared_articles.find_by_number(self.order_number) rescue nil
end
# convert units in foodcoop-size
diff --git a/app/models/order_article.rb b/app/models/order_article.rb
index bd90706b..3eb97aea 100644
--- a/app/models/order_article.rb
+++ b/app/models/order_article.rb
@@ -90,7 +90,8 @@ class OrderArticle < ActiveRecord::Base
end
def ordered_quantities_equal_to_group_orders?
- (units_to_order * price.unit_quantity) == group_orders_sum[:quantity]
+ # the rescue is a workaround for units_to_order not being defined in integration tests
+ (units_to_order * price.unit_quantity) == group_orders_sum[:quantity] rescue false
end
# Updates order_article and belongings during balancing process
diff --git a/app/models/user.rb b/app/models/user.rb
index f90f9602..3119e29d 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -17,7 +17,6 @@ class User < ActiveRecord::Base
has_many :assignments, :dependent => :destroy
has_many :tasks, :through => :assignments
has_many :send_messages, :class_name => "Message", :foreign_key => "sender_id"
- has_many :pages, :foreign_key => 'updated_by'
has_many :created_orders, :class_name => 'Order', :foreign_key => 'created_by_user_id', :dependent => :nullify
attr_accessor :password, :settings_attributes
diff --git a/app/views/articles/_destroy_active_article.haml b/app/views/articles/_destroy_active_article.haml
index 73c59e1c..90dcfae2 100644
--- a/app/views/articles/_destroy_active_article.haml
+++ b/app/views/articles/_destroy_active_article.haml
@@ -1,3 +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
+ = t('.note', article: h(@article.name), drop_link: link_to(t('.drop'), edit_order_path(@order))).html_safe
diff --git a/app/views/group_orders/_form.html.haml b/app/views/group_orders/_form.html.haml
index 14ca9303..a0b11791 100644
--- a/app/views/group_orders/_form.html.haml
+++ b/app/views/group_orders/_form.html.haml
@@ -9,7 +9,14 @@
// create List for search-feature (using list.js, http://listjs.com)
var listjsResetPlugin = ['reset', {highlightClass: 'btn-primary'}];
var listjsDelayPlugin = ['delay', {delayedSearchTime: 500}];
- new List(document.body, { valueNames: ['name'], engine: 'unlist', plugins: [listjsResetPlugin, listjsDelayPlugin] });
+ new List(document.body, {
+ valueNames: ['name'],
+ engine: 'unlist',
+ plugins: [listjsResetPlugin, listjsDelayPlugin],
+ // make large pages work too (as we don't have paging - articles may disappear!)
+ page: 10000,
+ indexAsync: true
+ });
});
- title t('.title'), false
diff --git a/app/views/home/_start_nav.haml b/app/views/home/_start_nav.haml
index 4f7f1b5c..346aa67a 100644
--- a/app/views/home/_start_nav.haml
+++ b/app/views/home/_start_nav.haml
@@ -4,7 +4,7 @@
%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"
+ %li= link_to t('.write_message'), new_message_path
- has_ordergroup = !@current_user.ordergroup.nil?
- has_orders_role = @current_user.role_orders?
diff --git a/app/views/home/ordergroup.html.haml b/app/views/home/ordergroup.html.haml
index 1fe79cbf..213ef0c9 100644
--- a/app/views/home/ordergroup.html.haml
+++ b/app/views/home/ordergroup.html.haml
@@ -4,16 +4,14 @@
.span4
%h2= @ordergroup.name
.well
+ - unless @ordergroup.description.blank?
+ %p= @ordergroup.description
%p
- %b= t '.description'
- = @ordergroup.description
- %p
- %b= t '.funds'
+ %b= Ordergroup.human_attribute_name(:available_funds) + ':'
= number_to_currency(@ordergroup.get_available_funds())
- %h2= t '.people'
- %ul
- - for membership in @ordergroup.memberships
- %li= show_user membership.user
+ %p
+ %b= Ordergroup.human_attribute_name(:user_tokens) + ':'
+ = @ordergroup.memberships.map{|m| show_user m.user}.join(', ')
= link_to t('.invite'), new_invite_path(:id => @ordergroup), :remote => true, class: 'btn btn-primary'
.span8
%h2= t('.account_summary')
diff --git a/app/views/home/profile.html.haml b/app/views/home/profile.html.haml
index 3b0a8abb..0b0364a1 100644
--- a/app/views/home/profile.html.haml
+++ b/app/views/home/profile.html.haml
@@ -5,7 +5,7 @@
%h3
= h(t('.user.title', user: show_user))
%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|
+ = simple_form_for(@current_user, :url => update_profile_path) do |f|
= render :partial => 'shared/user_form_fields', :locals => {:f => f}
.form-actions
= submit_tag t('ui.save'), class: 'btn'
diff --git a/app/views/layouts/application1.html.haml b/app/views/layouts/application1.html.haml
deleted file mode 100644
index c52e8003..00000000
--- a/app/views/layouts/application1.html.haml
+++ /dev/null
@@ -1,32 +0,0 @@
-!!!
-%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/login/forgot_password.html.haml b/app/views/login/forgot_password.html.haml
index 568ac258..c299f0ae 100644
--- a/app/views/login/forgot_password.html.haml
+++ b/app/views/login/forgot_password.html.haml
@@ -1,6 +1,6 @@
- title t('.title')
= t('.body').html_safe
-= simple_form_for User.new, url: {action: 'reset_password'} do |form|
+= simple_form_for User.new, url: reset_password_path do |form|
= form.input :email
.form-actions
= form.submit t('.submit'), class: 'btn'
diff --git a/app/views/login/new_password.html.haml b/app/views/login/new_password.html.haml
index f3fe19e5..2aa21e57 100644
--- a/app/views/login/new_password.html.haml
+++ b/app/views/login/new_password.html.haml
@@ -1,6 +1,6 @@
- title t('.title')
= raw t('.body', user: h(show_user(@user)))
-= simple_form_for @user, :url => {:action => 'update_password', :id => @user.id, :token => @user.reset_password_token} do |form|
+= simple_form_for @user, :url => update_password_path(@user.id, :token => @user.reset_password_token) do |form|
= form.input :password
= form.input :password_confirmation
.form-actions
diff --git a/app/views/orders/show.html.haml b/app/views/orders/show.html.haml
index 2a34807d..865a83c8 100644
--- a/app/views/orders/show.html.haml
+++ b/app/views/orders/show.html.haml
@@ -50,7 +50,7 @@
%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')}
+ %li= link_to t('.download.fax_txt'), order_path(@order, format: :txt), {title: t('.download.download_file')}
%section#articles_table
= render 'articles', order: @order
diff --git a/app/views/shared/_auto_complete_articles.html.haml b/app/views/shared/_auto_complete_articles.html.haml
deleted file mode 100644
index 84dda2d6..00000000
--- a/app/views/shared/_auto_complete_articles.html.haml
+++ /dev/null
@@ -1,4 +0,0 @@
-%ul.autocomplete
- - for article in @articles
- - supplier = @supplier ? "" : " - #{truncate(article.supplier.name)}"
- %li{:id => article.id.to_s}= "#{article.name} (#{article.unit_quantity} * #{article.unit} | #{number_to_currency(article.price)}#{supplier})"
diff --git a/app/views/shared/_auto_complete_users.rhtml b/app/views/shared/_auto_complete_users.rhtml
deleted file mode 100644
index 8a3a6ed4..00000000
--- a/app/views/shared/_auto_complete_users.rhtml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-<% for user in @users do -%>
- - <%= show_user(user) %> (<%= user.ordergroup.try(:name) %>)
-<% end -%>
-
diff --git a/app/views/shared/_loginInfo.haml b/app/views/shared/_loginInfo.haml
deleted file mode 100644
index 8ca136ec..00000000
--- a/app/views/shared/_loginInfo.haml
+++ /dev/null
@@ -1,9 +0,0 @@
-%ul
- %li
- = 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/memberships/_current_members.rhtml b/app/views/shared/memberships/_current_members.rhtml
deleted file mode 100644
index 18939041..00000000
--- a/app/views/shared/memberships/_current_members.rhtml
+++ /dev/null
@@ -1,21 +0,0 @@
-<% if flash[:error] %>
- <%= flash[:error] %>
- <%= javascript_tag("new Effect.Highlight('flashError', {delay:0.8, duration:1});") -%>
-<% end %>
-
-<% memberships = @group.memberships
- if memberships.size != 0 %>
-
- <% for membership in memberships %>
- -
- <%= show_user membership.user, full: true, markup: true %>
- | <%= link_to_remote t('.drop'),
- :url => { :controller => '/memberships', :action => 'drop_member', :id => @group, :membership_id => membership },
- :before => "Element.show('loader')",
- :success => "Element.hide('loader')" %>
-
- <% end %>
-
- <% else %>
-<%= t('.no_members', group: @group.name) %>
- <% end %>
diff --git a/app/views/shared/memberships/_members.rhtml b/app/views/shared/memberships/_members.rhtml
deleted file mode 100644
index 55a35452..00000000
--- a/app/views/shared/memberships/_members.rhtml
+++ /dev/null
@@ -1,23 +0,0 @@
-<%=h t('.title', group: @group.name) %>
-
- <%= t('.desc', link: remote_link_to(t('.invite'), :url => new_invite_path(:id => @group))).html_safe %>
-
-
-
-
<%= t('.already_members') %>
-
-
- <%=render :partial => 'shared/memberships/current_members' %>
-
-
-
-
-
<%= t('.no_members_yet') %>
-
-
- <%= render :partial => 'shared/memberships/non_members' %>
- <%= 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
deleted file mode 100644
index e741a13a..00000000
--- a/app/views/shared/memberships/_non_members.rhtml
+++ /dev/null
@@ -1,11 +0,0 @@
-
- <% for user in @group.non_members %>
- -
- <%= show_user user, full: true, markup: true %>
- | <%= 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 %>
-
diff --git a/app/views/tasks/_archive_tasks.html.haml b/app/views/tasks/_archive_tasks.html.haml
index 46250ddd..9ece4d05 100644
--- a/app/views/tasks/_archive_tasks.html.haml
+++ b/app/views/tasks/_archive_tasks.html.haml
@@ -13,5 +13,5 @@
- @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= link_to t('.task_format', name: task.name, duration: task.duration), task_path(task)
%td= task_assignments task
diff --git a/config/locales/de.yml b/config/locales/de.yml
index badf52ae..6c776a12 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -853,10 +853,7 @@ de:
no_ordergroups: Leider bist Du kein Mitglied einer Bestellgruppe
ordergroup:
account_summary: Kontoauszug
- description: Beschreibung
- funds: ! 'Verfügbares Guthaben:'
invite: Neue Person einladen
- people: Personen
search: Suchen ...
title: Meine Bestellgruppe
ordergroup_cancelled: Du bist jetzt kein Mitglied der Gruppe %{group} mehr.
@@ -906,8 +903,6 @@ de:
ordering:
confirm_change: Änderungen an dieser Bestellung gehen verloren, wenn zu einer anderen Bestellung gewechselt wird. Möchtest Du trotzdem wechseln?
layouts:
- application1:
- title: Foodsoft - %{title}
email:
footer: ! '--
@@ -1367,28 +1362,6 @@ de:
search_user: Nach Nutzerin suchen
title: Wöchentliche Jobs
user_not_found: Keine Nutzerin gefunden
- loginInfo:
- edit_profile: Profil bearbeiten
- feedback:
- desc: Fehler gefunden? Vorschlag? Idee? Kritik?
- title: Feedback
- help: Hilfe
- homepage_title: Foodcoop Homepage besuchen
- logout: Abmelden
- profile: Profil
- memberships:
- current_members:
- drop: entfernen
- no_members: ! '%{group} hat keine Mitglieder.'
- members:
- already_members: Sind schon Mitglieder
- desc: Hier kannst Du Mitglieder der Gruppe verwalten oder ein neues Foodcoop-Mitglied in die Gruppe %{link}.
- invite: einladen
- invite_someone: Person einladen
- no_members_yet: Sind noch keine Mitglieder
- title: Mitglieder von %{group}
- non_members:
- add: hinzufügen
open_orders:
ending: Ende
no_open_orders: Derzeit gibt es keine laufenden Bestellungen
@@ -1416,7 +1389,6 @@ de:
name: Bitte ändern
edit_stock_article:
price: - Preisänderung gesperrt.
- Bei Bedarf %{stock_article_copy_link}.
- supplier:
supplier:
min_order_quantity: Die Mindestbestellmenge wird während der Bestellung angezeigt und soll motivieren
task:
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 5e547a03..63b87afc 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -646,7 +646,7 @@ en:
title: Invoice %{number}
order_articles:
edit:
- stock_alert:
+ stock_alert: The price of stock articles cannot be changed!
title: Update article
new:
title: Add delivered article to order
@@ -858,10 +858,7 @@ en:
no_ordergroups: You are unfortunately not a member of an ordergroup.
ordergroup:
account_summary: Account Statement
- description: description
- funds: ! 'Available credit:'
invite: Invite a new Person
- people: People
search: Search ...
title: My ordergroup
ordergroup_cancelled: You cancelled membership of the group %{group}.
@@ -911,8 +908,6 @@ en:
ordering:
confirm_change: Modifications to this order will be lost when you change the order. Do you want to lose the changes you made and continue?
layouts:
- application1:
- title: Foodsoft - %{title}
email:
footer: ! '--
@@ -1372,28 +1367,6 @@ en:
search_user: Search user
title: Weekly jobs
user_not_found: No user found
- loginInfo:
- edit_profile: Edit profile
- feedback:
- desc: Found a bug? Suggestions? Review?
- title: Feedback
- help: Help
- homepage_title: Visit Foodcoop Homepage
- logout: Logout
- profile: Profile
- memberships:
- current_members:
- drop: remove
- no_members: ! '%{group} has no members.'
- members:
- already_members: Are already members
- desc: Here you can manage members of the group or invite a new Foodcoop-member to the group %{link}.
- invite: invite
- invite_someone: Invite someone
- no_members_yet: Are not members yet
- title: Members of %{group}
- non_members:
- add: add
open_orders:
ending: Ending
no_open_orders: There are no current orders
@@ -1421,7 +1394,6 @@ en:
name: Please modify
edit_stock_article:
price: - Price changes are forbidden.
- If necessary, %{stock_article_copy_link}.
- supplier:
supplier:
min_order_quantity: The minimum amount which has to be orderd will be shown during the order process and should motivate ordering
task:
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index 0a495014..f5e54531 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -879,10 +879,7 @@ fr:
no_ordergroups: Tu ne fais encore partie d'aucune cellule
ordergroup:
account_summary: Relevé de compte
- description: Description
- funds: ! 'Crédit disponible:'
invite: Engrainer une nouvelle personne
- people: Personnes
search: Rechercher ...
title: Ta cellule
ordergroup_cancelled: Tu ne fais plus partie de la cellule %{group}.
@@ -932,8 +929,6 @@ fr:
ordering:
confirm_change:
layouts:
- application1:
- title: Foodsoft - %{title}
email:
footer: ! '--
@@ -1374,28 +1369,6 @@ fr:
search_user: Rechercher par utilisatrice
title: Boulots hebdomadaires
user_not_found: Aucune utilisatrice n'a été trouvée.
- loginInfo:
- edit_profile: Modifier le profil
- feedback:
- desc: Tu as détecté une erreur? Tu as des propositions, des idées, des critiques?
- title: Retours
- help: Aide
- homepage_title: Vers la page d'accueil de la bouffecoop
- logout: Te déconnecter
- profile: Profil
- memberships:
- current_members:
- drop: désinscrire
- no_members: ! '%{group} n''a aucun membre pour le moment.'
- members:
- already_members: Sont déjà membre
- desc: Sur cette page, tu peux gérer les membres de l'équipe, et aussi %{link} un nouveau membre.
- invite: engrainer
- invite_someone: Inviter quelqu'unE
- no_members_yet: Ne sont pas encore membre
- title: Membre de %{group}
- non_members:
- add: ajouter
open_orders:
ending: Clôture le
no_open_orders: Il n'y a aucune commande en cours en ce moment
@@ -1423,7 +1396,6 @@ fr:
name: Merci de modifier
edit_stock_article:
price: - Modification du prix enregistrée.
- Si nécessaire %{stock_article_copy_link}.
- supplier:
supplier:
min_order_quantity: La quantité minimum à commander est affichée pendant la commande et doit motiver
task:
diff --git a/config/locales/nl.yml b/config/locales/nl.yml
index fba0e912..02fa13d4 100644
--- a/config/locales/nl.yml
+++ b/config/locales/nl.yml
@@ -26,15 +26,15 @@ nl:
description: Omschrijving
name: Naam
delivery:
- delivered_on:
- note:
- supplier:
+ delivered_on: Leverdatum
+ note: Notitie
+ supplier: Leverancier
financial_transaction:
amount: bedrag
note: notitie
group_order_article:
- ordergroup_id:
- result:
+ ordergroup_id: Huishouden
+ result: Hoeveelheid
invoice:
amount: Bedrag
date: Factuurdatum
@@ -47,12 +47,12 @@ nl:
paid_on: Betaald op
supplier: Leverancier
message:
- body:
- group_id:
- private:
- recipient_tokens:
- sent_to_all:
- subject:
+ body: Bericht
+ group_id: Groep
+ private: Privé
+ recipient_tokens: Geadresseerden
+ sent_to_all: Aan alle leden sturen
+ subject: Onderwerp
order:
ends: Eindigt op
note: Notitie
@@ -71,22 +71,22 @@ nl:
name: Naam
user_tokens: Leden
page:
- body:
+ body: Bericht
parent_id:
- title:
+ title: Titel
stock_article:
price: Prijs
quantity: Aantal
quantity_available: Beschikbaar
supplier: Leverancier
stock_taking:
- date:
- note:
+ date: Datum
+ note: Notitie
supplier:
address: Adres
contact_person: Contactpersoon
customer_number: Klantnummer
- customer_number_short:
+ customer_number_short: Klantnr.
delivery_days: Bezorgdagen
email: Email
fax: Fax
@@ -99,14 +99,14 @@ nl:
phone2: Telefoon 2
url: Homepage
task:
- description:
- done:
- due_date:
- duration:
- name:
- required_users:
- user_list:
- workgroup:
+ description: Beschrijving
+ done: Gedaan?
+ due_date: Voor wanneer?
+ duration: Tijdsduur
+ name: Naam
+ required_users: Aantal
+ user_list: Verantwoordelijken
+ workgroup: Werkgroep
user:
email: Email
first_name: Voornaam
@@ -123,7 +123,7 @@ nl:
workgroup:
description: Omschrijving
name: Naam
- next_weekly_tasks_number:
+ next_weekly_tasks_number: Hoeveel weken vooruit moet de taak zichtbaar zijn?
role_admin: Beheer
role_article_meta: Artikelen
role_finance: Financiën
@@ -297,7 +297,7 @@ nl:
error_parse: ! '%{msg} ... in regel %{line}'
error_update: ! 'Er trad een fout op bij het bijwerken van artikel ''%{article}'': %{msg}'
parse_upload:
- notice: ! '%{count} artikel zijn geanalyseerd'
+ notice: ! '%{count} artikelen zijn geanalyseerd'
sync:
notice: Catalogus is bijgewerkt
shared_alert: ! '%{supplier} is niet aan een externe database gekoppeld'
@@ -393,9 +393,9 @@ nl:
title:
form:
actions:
- article:
- category:
- create_from_blank:
+ article: Artikel
+ category: Categorie
+ create_from_blank: Nieuwe artikel invoeren
create_stock_article:
price:
quantity:
@@ -639,7 +639,7 @@ nl:
title: Factuur %{number}
order_articles:
edit:
- stock_alert:
+ stock_alert: De prijs van voorraadartikelen kan niet aangepast worden!
title: Artikel bijwerken
new:
title: Geleverd artikel aan bestelling toevoegen
@@ -850,10 +850,7 @@ nl:
no_ordergroups: Jammergenoeg ben je niet aangesloten bij een huishouden.
ordergroup:
account_summary: Rekeningafschrift
- description: Omschrijving
- funds: ! 'Beschikbaar krediet:'
invite: Iemand uitnodigen
- people: Personen
search: Zoeken ...
title: Mijn huishouden
ordergroup_cancelled: Je bent geen lid meer van de groep %{group}.
@@ -903,8 +900,6 @@ nl:
ordering:
confirm_change:
layouts:
- application1:
- title: Foodsoft - %{title}
email:
footer: ! '--
@@ -1279,7 +1274,7 @@ nl:
price: Totaalprijs
articles_by_groups:
fc_price: FC-Prijs
- fc_price_desc: Prijs inclusief belasting, borg en foodcoop-toeslag
+ fc_price_desc: Prijs inclusief belasting, statiegeld en foodcoop marge
name: Naam
price: Totaalprijs
unit: Eenheid
@@ -1301,28 +1296,6 @@ nl:
search_user: Gebruiker zoeken
title: Wekelijkse taken
user_not_found: Geen gebruiker gevonden
- loginInfo:
- edit_profile: Profiel aanpassen
- feedback:
- desc: Fout gevonden? Opmerking? Idee?
- title: Feedback
- help: Help
- homepage_title: Foodcoop startpagina bezoeken
- logout: Uitloggen
- profile: Profiel
- memberships:
- current_members:
- drop: verwijderen
- no_members: ! '%{group} heeft geen leden.'
- members:
- already_members: Zijn al lid
- desc:
- invite: uitnodiging
- invite_someone: Iemand uitnodigen
- no_members_yet: Zijn nog geen lid
- title: Leden van %{group}
- non_members:
- add: toevoegen
open_orders:
ending: Einde
no_open_orders: Er zijn momenteel geen lopende bestellingen.
@@ -1350,7 +1323,6 @@ nl:
name:
edit_stock_article:
price:
- supplier:
supplier:
min_order_quantity:
task:
diff --git a/config/navigation.rb b/config/navigation.rb
index 74b76bbe..49a3293d 100644
--- a/config/navigation.rb
+++ b/config/navigation.rb
@@ -3,6 +3,11 @@
SimpleNavigation::Configuration.run do |navigation|
+ # allow engines to add to the menu - https://gist.github.com/mjtko/4873ee0c112b6bd646f8
+ engines = Rails.application.railties.engines.select { |e| e.respond_to?(:navigation) }
+ # to include an engine but keep it from modifying the menu:
+ #engines.reject! { |e| e.instance_of? FoodsoftMyplugin::Engine }
+
navigation.items do |primary|
primary.dom_class = 'nav'
@@ -16,11 +21,6 @@ SimpleNavigation::Configuration.run do |navigation|
subnav.item :tasks, I18n.t('navigation.tasks'), tasks_path, id: nil
end
- primary.item :wiki, I18n.t('navigation.wiki.title'), '#', id: nil do |subnav|
- subnav.item :wiki_home, I18n.t('navigation.wiki.home'), wiki_path, id: nil
- subnav.item :all_pages, I18n.t('navigation.wiki.all_pages'), all_pages_path, id: nil
- end
-
primary.item :orders, I18n.t('navigation.orders.title'), '#', id: nil do |subnav|
subnav.item :ordering, I18n.t('navigation.orders.ordering'), group_orders_path, id: nil
subnav.item :ordering_archive, I18n.t('navigation.orders.archive'), archive_group_orders_path, id: nil
@@ -47,6 +47,8 @@ SimpleNavigation::Configuration.run do |navigation|
subnav.item :ordergroups, I18n.t('navigation.admin.ordergroups'), admin_ordergroups_path, id: nil
subnav.item :workgroups, I18n.t('navigation.admin.workgroups'), admin_workgroups_path, id: nil
end
+
+ engines.each { |e| e.navigation(primary, self) }
end
end
diff --git a/config/routes.rb b/config/routes.rb
index 533d2d97..655a1038 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -18,27 +18,20 @@ Foodsoft::Application.routes.draw do
match '/login' => 'sessions#new', :as => 'login'
match '/logout' => 'sessions#destroy', :as => 'logout'
- get '/login/forgot_password' => 'login#forgot_password', as: :forgot_password
- get '/login/new_password' => 'login#new_password', as: :new_password
+ get '/login/forgot_password' => 'login#forgot_password', as: :forgot_password
+ post '/login/reset_password' => 'login#reset_password', as: :reset_password
+ get '/login/new_password' => 'login#new_password', as: :new_password
+ get '/login/update_password' => 'login#update_password', as: :update_password
match '/login/accept_invitation/:token' => 'login#accept_invitation', as: :accept_invitation
resources :sessions, :only => [:new, :create, :destroy]
########### User specific
match '/home/profile' => 'home#profile', :as => 'my_profile'
+ put '/home/update_profile' => 'home#update_profile', :as => 'update_profile'
match '/home/ordergroup' => 'home#ordergroup', :as => 'my_ordergroup'
match '/home/cancel_membership' => 'home#cancel_membership', :as => 'cancel_membership'
- ############ Wiki
-
- resources :pages do
- get :all, :on => :collection
- get :version, :on => :member
- get :revert, :on => :member
- end
- match '/wiki/:permalink' => 'pages#show', :as => 'wiki_page' # , :constraints => {:permalink => /[^\s]+/}
- match '/wiki' => 'pages#show', :defaults => {:permalink => 'Home'}, :as => 'wiki'
-
############ Orders, ordering
resources :orders do
@@ -191,8 +184,5 @@ Foodsoft::Application.routes.draw do
resources :users, :only => [:index]
- # TODO: This is very error prone. Better deactivate this catch all route
- match ':controller(/:action(/:id))(.:format)'
-
end # End of /:foodcoop scope
end
diff --git a/db/migrate/20090325175756_create_pages.foodsoft_wiki_engine.rb b/db/migrate/20090325175756_create_pages.foodsoft_wiki_engine.rb
new file mode 100644
index 00000000..dc8cb3bc
--- /dev/null
+++ b/db/migrate/20090325175756_create_pages.foodsoft_wiki_engine.rb
@@ -0,0 +1,24 @@
+# This migration comes from foodsoft_wiki_engine (originally 20090325175756)
+class CreatePages < ActiveRecord::Migration
+ def self.up
+ create_table :pages do |t|
+ t.string :title
+ t.text :body
+ t.string :permalink
+ t.integer :lock_version, :default => 0
+ t.integer :updated_by
+ t.integer :redirect
+ t.integer :parent_id
+
+ t.timestamps
+ end
+ add_index :pages, :title
+ add_index :pages, :permalink
+ Page.create_versioned_table # Automaticly creates pages_versions table
+ end
+
+ def self.down
+ drop_table :pages
+ Page.drop_versioned_table
+ end
+end
diff --git a/doc/BESTELLEN.md b/doc/BESTELLEN.md
new file mode 100644
index 00000000..092827eb
--- /dev/null
+++ b/doc/BESTELLEN.md
@@ -0,0 +1,93 @@
+
+# Bestellen
+Das Bestellen ist der Hauptteil dieser Software und ein wenig kompliziert.
+Hier starte ich den Versuch die Programmlogik in Text umzusetzen und
+verweise auf die enstprechenden Controller bzw. Modelle.
+Der relevante Controller ist `OrdersController`.
+
+## Bestellung "in Netz stellen"
+Darunter verstehen wir die Auswahl von Artikeln eines bestimmten Lieferanten fuer eine zeitlich begrenzte
+Bestellung im Internet. Die relevanten Methoden sind `OrdersController#newOrder` und folgende.
+Jede Bestellung wird durch die Klasse Order abgebildet.
+
+Die zugehoerigen Artikel werden duch die Klasse `OrderArticle` mit den Artikeln verknuepft.
+Dabei werden auch die Attribute `quantity`, `tolerance` und `quantity_to_order` gespeichert.
+Diese Mengen repraesentieren die Gesamtbestellung, also alle Bestellgruppen.
+
+## Eine Bestellgruppe bestellt...
+Die Methode `OrdersController#order` schickt uns die Bestellenseite. Mit dieser
+Oberflaeche koennen die Bestellgruppena die vorher ausgewaehlten Artikel
+bestellen. Mittels den Buttons werden dabei live, also clientseitig, die
+Preise ermittelt und der Gesamtpreis berechnet. Ist der Gesamtpreis groeßer als
+der aktuelle Gruppenkontostand, so wird die Preisspalte rot unterlegt und die
+Bestellung kann nicht gespeichert werden.
+
+## (gruppen)-Bestellung wird gespeichert
+
+Die Gruppenbestellung wird durch die Tabelle `group_oders` (`GroupOrder`)
+abgebildet, bzw. die Bestellung und Bestellgruppe wird dort verknuepft.
+
+Die bestellten Artikel der Bestellgruppe werden durch die Tabelle `group_order_articles`
+(`GroupOrderArticle`) registriert. Dort werden nun die Modelle GroupOrder
+und OrderArticle miteinander verbunden.
+
+Bei jeder Bestellung wird außerdem die Summe der Menge, Toleranz in `GroupOrderArticle`
+abgelegt. Allerdings muss jede Aenderung dieser Mengen mit protokolliert werden.
+Dies ist wichtig, weil spaeter die Zuteilung der Einheiten pro bestellten Artikel
+nach der chronologischen Reihenfolge erfolgt. (s.u.)
+Das passiert dann in der Tabelle `group_order_article_quantities`
+(`GroupOrderArticleQuantity`).
+
+## Aenderunug einer Bestellung
+
+Knifflig ist die Aenderung einer gruppenbestellung, weil die zeitliche
+Reihenfolge dabei nicht durcheinander geraten darf.
+Wir unterscheiden dehalb zwei Faelle:
+
+### Erhoehe die Menge des Arikels.
+Jetzt wird eine Zeile in `group_order_article_quantities` angelegt.
+und zwar mit genau den Mengen, die zusatzlich bestellt wurden.
+Quantity und Tolerance funktionieren analog.
+
+Beispiel:
+* Urspruenglich bestellt: 2(2) um 17uhr.
+* Erhoehe Bestellung auf 4(2) um 18hur.
+ => neue Zeile mit quantity = 2, tolerance = 0, und created_on = 18uhr
+* Jetzt gibt es zwei zeilen die insgesamt 4(2) ergeben.
+ (die summen in `GroupOrderArticle` werden aktualisiert)
+
+### Verringere die Mengen des Artikels.
+Jetzt muss chronologisch zurueckgegangen werden und um die urspruenglich bestellten
+Mengen zu verringern.
+
+Beispiel von oben:
+* Verringe Bestellung auf 2(1) um 19uhr.
+ => Zeile mit created_on = 18uhr wird gelöscht und
+ in der Zeile mit created_on = 17uhr wird der Wert tolerance auf 1 gaendert.
+
+## Wer bekommt wieviel?
+
+Diese Frage wird wie schon erwaehnt mittels der `group_order_article_quantites`-Tabelle
+geloest.
+
+Beispiel.
+
+* articel x mit unit_quantity = 5.
+ * 17uhr: gruppe a bestellt 2(3), weil sie auf jeden fall was von x bekommen will
+ * 18uhr: gruppe b bestellt 2(0)
+ * 19uhr: gruppe a faellt ein dass sie doch noch mehr braucht von x und aendert auf 4(1).
+
+* jetzt gibt es drei zeilen in der tabelle, die so aussehen:
+ * (gruppe a), 2(1), 17uhr (wurde um 19uhr von 2(3) auf 2(1) geaendert)
+ * (gruppe b), 2(0), 18uhr
+ * (gruppe a), 2(0), 19uhr.
+
+* die zuteilung wird dann wie folgt ermittelt:
+ * zeile 1: gruppe a bekommt 2
+ * zeile 2: gruppe b bekommt 2
+ * zeile 3: gruppe a bekommt 1, weil jetzt das gebinde schon voll ist.
+
+* Endstand: insg. Bestellt wurden 6(1)
+ * Gruppe a bekommt 3 einheiten.
+ * gruppe b bekommt 2 einheiten.
+ * eine Einheit verfaellt.
diff --git a/doc/README_FOR_APP.md b/doc/README_FOR_APP.md
deleted file mode 100644
index 0f25c510..00000000
--- a/doc/README_FOR_APP.md
+++ /dev/null
@@ -1,94 +0,0 @@
-Use this README file to introduce your application and point to useful places in the API for learning more.
-Run "rake doc:app" to generate API documentation for your models and controllers.
-
-= The Foodsoft
-
-is a Web-based software to manage a non-profit food coop (product catalog, ordering, accounting, job scheduling).
-
-
-== Bestellen
-Das Bestellen ist der Hauptteil dieser Software und ein wenig kompliziert.
-Hier starte ich den Versuch die Programmlogik in Text umzusetzen und
-verweise auf die enstprechenden Controller bzw. Modelle.
-Der relevante Controller ist OrderingController.
-
-=== Bestellung "in Netz stellen"
-Darunter verstehen wir die Auswahl von Artikeln eines bestimmten Lieferanten fuer eine zeitlich begrenzte
-Bestellung im Internet. Die relevanten Methoden sind OrdersController#newOrder und folgende.
-Jede Bestellung wird durch die Klasse Order abgebildet.
-
-Die zugehoerigen Artikel werden duch die Klasse OrderArticle mit den Artikeln verknuepft.
-Dabei werden auch die Attribute quantity, tolerance und quantity_to_order gespeichert.
-Diese Mengen repraesentieren die Gesamtbestellung, also alle Bestellgruppen.
-
-=== Eine Bestellgruppe bestellt...
-Die Methode OrdersController#order schickt uns die Bestellenseite. Mit dieser Oberflaeche
-koennen die Bestellgruppena die vorher ausgewaehlten Artikel bestellen.
-Mittels den Buttons werden dabei live, also clientseitig, die Preise ermittelt
-und der Gesamtpreis berechnet. Ist der Gesamtpreis groeßer als der aktuelle
-Gruppenkontostand, so wird die Preisspalte rot unterlegt und die Bestellung
-kann nicht gespeichert werden.
-
-=== (gruppen)-Bestellung wird gespeichert
-
-Die Gruppenbestellung wird durch die Tabelle group_oders (GroupOrder)
-abgebildet, bzw. die Bestellung und Bestellgruppe wird dort verknuepft.
-
-Die bestellten Artikel der Bestellgruppe werden durch die Tablle group_order_articles
-(GroupOrderArticle) registriert. Dort werden nun die Modelle GroupOrder
-und OrderArticle miteinander verbunden.
-
-Bei jeder Bestellung wird außerdem die Summe der Menge, Toleranz in GroupOrderArticle
-abgelegt. Allerdings muss jede Aenderung dieser Mengen mit protokolliert werden.
-Dies ist wichtig, weil spaeter die Zuteilung der Einheiten pro bestellten Artikel
-nach der chronologischen Reihenfolge erfolgt. (s.u.)
-Das passiert dann in der Tabelle group_order_article_quantities.
-(GroupOrderArticleQuantity)
-
-=== Aenderunug einer Bestellung
-
-Knifflig ist die Aenderung einer gruppenbestellung, weil die zeitliche
-Reihenfolge dabei nicht durcheinander geraten darf.
-Wir unterscheiden dehalb zwei Faelle:
-==== Erhoehe die Menge des Arikels.
- Jetzt wird eine Zeile in group_order_article_quantities angelegt.
- und zwar mit genau den Mengen, die zusatzlich bestellt wurden.
- Quantity und Tolerance funktionieren analog.
- Beispiel:
- Urspruenglich bestellt: 2(2) um 17uhr.
- Erhoehe Bestellung auf 4(2) um 18hur.
- => neue Zeile mit quantity= 2, tolerance = 0, und created_on = 18uhr
- Jetzt gibt es zwei zeilen die insgesamt 4(2) ergeben.
- (die summen in GroupOrderArticle werden aktualisiert)
-==== Verringere die Mengen des Artikels.
- Jetzt muss chronologisch zurueckgegangen werden und um die urspruenglich bestellten
- Mengen zu verringern.
- Beispiel von oben:
- Verringe Bestellung auf 2(1) um 19uhr.
- => Zeile mit created_on = 18uhr wird gelöscht und
- in der Zeile mit created_on = 17uhr wird der Wert tolerance auf 1 gaendert.
-
-=== Wer bekommt wieviel?
-
-Diese Frage wird wie schon erwaehnt mittels der group_order_article_quantites -Tabelle
-geloest.
-Beipspiel.
- articel x mit unit_quantity = 5.
- 17uhr: gruppe a bestellt 2(3), weil sie auf jeden fall was von x bekommen will
- 18uhr: gruppe b bestellt 2(0)
- 19uhr: gruppe a faellt ein dass sie doch noch mehr braucht von x und aendert auf 4(1).
-
- jetzt gibt es drei zeilen in der tabelle, die so aussehen:
- (gruppe a), 2(1), 17uhr (wurde um 19uhr von 2(3) auf 2(1) geaendert)
- (gruppe b), 2(0), 18uhr
- (gruppe a), 2(0), 19uhr.
-
- die zuteilung wird dann wie folgt ermittelt:
- zeile 1: gruppe a bekommt 2
- zeile 2: gruppe b bekommt 2
- zeile 3: gruppe a bekommt 1, weil jetzt das gebinde schon voll ist.
-
- Endstand: insg. Bestellt wurden 6(1)
- Gruppe a bekommt 3 einheiten.
- gruppe b bekommt 2 einheiten.
- eine Einheit verfaellt.
diff --git a/doc/SETUP_DEVELOPMENT.md b/doc/SETUP_DEVELOPMENT.md
index 18a2b16f..9941c262 100644
--- a/doc/SETUP_DEVELOPMENT.md
+++ b/doc/SETUP_DEVELOPMENT.md
@@ -66,7 +66,7 @@ If you want to have more control, you can do these steps manually as
explained here.
-1. **Configure datebase**
+1. **Configure database**
Create the database configuration from the default:
```sh
diff --git a/lib/foodsoft_wiki/README.md b/lib/foodsoft_wiki/README.md
new file mode 100644
index 00000000..dcf2f18c
--- /dev/null
+++ b/lib/foodsoft_wiki/README.md
@@ -0,0 +1,18 @@
+FoodsoftWiki
+============
+
+This plugin adds wiki pages to foodsoft. A new 'Wiki' menu is added next to
+the 'Foodcoops' menu in the navigation bar.
+
+This plugin is enabled by default in foodsoft, so you don't need to do anything
+to install it. If you still want to, for example when it has been disabled,
+add the following to foodsoft's Gemfile:
+
+```Gemfile
+# we use the git version of acts_as_versioned, so this needs to be in foodsoft's Gemfile
+gem 'acts_as_versioned', git: 'git://github.com/technoweenie/acts_as_versioned.git'
+gem 'foodsoft_wiki', path: 'lib/foodsoft_wiki'
+```
+
+This plugin is part of the foodsoft package and uses the GPL-3 license (see
+foodsoft's LICENSE for the full license text).
diff --git a/lib/foodsoft_wiki/Rakefile b/lib/foodsoft_wiki/Rakefile
new file mode 100644
index 00000000..a3d12088
--- /dev/null
+++ b/lib/foodsoft_wiki/Rakefile
@@ -0,0 +1,40 @@
+#!/usr/bin/env rake
+begin
+ require 'bundler/setup'
+rescue LoadError
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
+end
+begin
+ require 'rdoc/task'
+rescue LoadError
+ require 'rdoc/rdoc'
+ require 'rake/rdoctask'
+ RDoc::Task = Rake::RDocTask
+end
+
+RDoc::Task.new(:rdoc) do |rdoc|
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = 'FoodsoftWiki'
+ rdoc.options << '--line-numbers'
+ rdoc.rdoc_files.include('README.rdoc')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
+
+APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
+load 'rails/tasks/engine.rake'
+
+
+
+Bundler::GemHelper.install_tasks
+
+require 'rake/testtask'
+
+Rake::TestTask.new(:test) do |t|
+ t.libs << 'lib'
+ t.libs << 'test'
+ t.pattern = 'test/**/*_test.rb'
+ t.verbose = false
+end
+
+
+task :default => :test
diff --git a/app/controllers/pages_controller.rb b/lib/foodsoft_wiki/app/controllers/pages_controller.rb
similarity index 100%
rename from app/controllers/pages_controller.rb
rename to lib/foodsoft_wiki/app/controllers/pages_controller.rb
diff --git a/app/helpers/pages_helper.rb b/lib/foodsoft_wiki/app/helpers/pages_helper.rb
similarity index 100%
rename from app/helpers/pages_helper.rb
rename to lib/foodsoft_wiki/app/helpers/pages_helper.rb
diff --git a/app/models/page.rb b/lib/foodsoft_wiki/app/models/page.rb
similarity index 100%
rename from app/models/page.rb
rename to lib/foodsoft_wiki/app/models/page.rb
diff --git a/app/views/pages/_body.html.haml b/lib/foodsoft_wiki/app/views/pages/_body.html.haml
similarity index 100%
rename from app/views/pages/_body.html.haml
rename to lib/foodsoft_wiki/app/views/pages/_body.html.haml
diff --git a/app/views/pages/_form.html.haml b/lib/foodsoft_wiki/app/views/pages/_form.html.haml
similarity index 100%
rename from app/views/pages/_form.html.haml
rename to lib/foodsoft_wiki/app/views/pages/_form.html.haml
diff --git a/app/views/pages/_page_list_item.html.haml b/lib/foodsoft_wiki/app/views/pages/_page_list_item.html.haml
similarity index 100%
rename from app/views/pages/_page_list_item.html.haml
rename to lib/foodsoft_wiki/app/views/pages/_page_list_item.html.haml
diff --git a/app/views/pages/_recent_changes.html.haml b/lib/foodsoft_wiki/app/views/pages/_recent_changes.html.haml
similarity index 100%
rename from app/views/pages/_recent_changes.html.haml
rename to lib/foodsoft_wiki/app/views/pages/_recent_changes.html.haml
diff --git a/app/views/pages/_site_map.html.haml b/lib/foodsoft_wiki/app/views/pages/_site_map.html.haml
similarity index 100%
rename from app/views/pages/_site_map.html.haml
rename to lib/foodsoft_wiki/app/views/pages/_site_map.html.haml
diff --git a/app/views/pages/_title_list.html.haml b/lib/foodsoft_wiki/app/views/pages/_title_list.html.haml
similarity index 100%
rename from app/views/pages/_title_list.html.haml
rename to lib/foodsoft_wiki/app/views/pages/_title_list.html.haml
diff --git a/app/views/pages/all.html.haml b/lib/foodsoft_wiki/app/views/pages/all.html.haml
similarity index 100%
rename from app/views/pages/all.html.haml
rename to lib/foodsoft_wiki/app/views/pages/all.html.haml
diff --git a/app/views/pages/edit.html.haml b/lib/foodsoft_wiki/app/views/pages/edit.html.haml
similarity index 100%
rename from app/views/pages/edit.html.haml
rename to lib/foodsoft_wiki/app/views/pages/edit.html.haml
diff --git a/app/views/pages/new.html.haml b/lib/foodsoft_wiki/app/views/pages/new.html.haml
similarity index 100%
rename from app/views/pages/new.html.haml
rename to lib/foodsoft_wiki/app/views/pages/new.html.haml
diff --git a/app/views/pages/show.html.haml b/lib/foodsoft_wiki/app/views/pages/show.html.haml
similarity index 100%
rename from app/views/pages/show.html.haml
rename to lib/foodsoft_wiki/app/views/pages/show.html.haml
diff --git a/app/views/pages/version.html.haml b/lib/foodsoft_wiki/app/views/pages/version.html.haml
similarity index 100%
rename from app/views/pages/version.html.haml
rename to lib/foodsoft_wiki/app/views/pages/version.html.haml
diff --git a/lib/foodsoft_wiki/config/routes.rb b/lib/foodsoft_wiki/config/routes.rb
new file mode 100644
index 00000000..29a5ebef
--- /dev/null
+++ b/lib/foodsoft_wiki/config/routes.rb
@@ -0,0 +1,15 @@
+Rails.application.routes.draw do
+
+ scope '/:foodcoop' do
+
+ resources :pages do
+ get :all, :on => :collection
+ get :version, :on => :member
+ get :revert, :on => :member
+ end
+ match '/wiki/:permalink' => 'pages#show', :as => 'wiki_page' # , :constraints => {:permalink => /[^\s]+/}
+ match '/wiki' => 'pages#show', :defaults => {:permalink => 'Home'}, :as => 'wiki'
+
+ end
+
+end
diff --git a/db/migrate/20090325175756_create_pages.rb b/lib/foodsoft_wiki/db/migrate/20090325175756_create_pages.rb
similarity index 100%
rename from db/migrate/20090325175756_create_pages.rb
rename to lib/foodsoft_wiki/db/migrate/20090325175756_create_pages.rb
diff --git a/lib/foodsoft_wiki/foodsoft_wiki.gemspec b/lib/foodsoft_wiki/foodsoft_wiki.gemspec
new file mode 100644
index 00000000..937a887f
--- /dev/null
+++ b/lib/foodsoft_wiki/foodsoft_wiki.gemspec
@@ -0,0 +1,24 @@
+$:.push File.expand_path("../lib", __FILE__)
+
+# Maintain your gem's version:
+require "foodsoft_wiki/version"
+
+# Describe your gem and declare its dependencies:
+Gem::Specification.new do |s|
+ s.name = "foodsoft_wiki"
+ s.version = FoodsoftWiki::VERSION
+ s.authors = ["wvengen"]
+ s.email = ["dev-foodsoft@willem.engen.nl"]
+ s.homepage = "https://github.com/foodcoops/foodsoft"
+ s.summary = "Wiki plugin for foodsoft."
+ s.description = "Adds a wiki to foodsoft."
+
+ s.files = Dir["{app,config,db,lib}/**/*"] + ["Rakefile", "README.md"]
+ s.test_files = Dir["test/**/*"]
+
+ s.add_dependency "rails", "~> 3.2.15"
+ s.add_dependency 'wikicloth'
+ s.add_dependency 'acts_as_versioned' # need git version, make sure that is included in foodsoft's Gemfile
+
+ s.add_development_dependency "sqlite3"
+end
diff --git a/lib/foodsoft_wiki/lib/foodsoft_wiki.rb b/lib/foodsoft_wiki/lib/foodsoft_wiki.rb
new file mode 100644
index 00000000..acf5ef50
--- /dev/null
+++ b/lib/foodsoft_wiki/lib/foodsoft_wiki.rb
@@ -0,0 +1,6 @@
+require 'wikicloth'
+require 'acts_as_versioned'
+require 'foodsoft_wiki/engine'
+
+module FoodsoftWiki
+end
diff --git a/lib/foodsoft_wiki/lib/foodsoft_wiki/engine.rb b/lib/foodsoft_wiki/lib/foodsoft_wiki/engine.rb
new file mode 100644
index 00000000..68f0ab7f
--- /dev/null
+++ b/lib/foodsoft_wiki/lib/foodsoft_wiki/engine.rb
@@ -0,0 +1,14 @@
+module FoodsoftWiki
+ class Engine < ::Rails::Engine
+ def navigation(primary, ctx)
+ primary.item :wiki, I18n.t('navigation.wiki.title'), '#', id: nil do |subnav|
+ subnav.item :wiki_home, I18n.t('navigation.wiki.home'), ctx.wiki_path, id: nil
+ subnav.item :all_pages, I18n.t('navigation.wiki.all_pages'), ctx.all_pages_path, id: nil
+ end
+ # move this last added item to just after the foodcoop menu
+ if i = primary.items.index(primary[:foodcoop])
+ primary.items.insert(i+1, primary.items.delete_at(-1))
+ end
+ end
+ end
+end
diff --git a/lib/foodsoft_wiki/lib/foodsoft_wiki/version.rb b/lib/foodsoft_wiki/lib/foodsoft_wiki/version.rb
new file mode 100644
index 00000000..2a67a94e
--- /dev/null
+++ b/lib/foodsoft_wiki/lib/foodsoft_wiki/version.rb
@@ -0,0 +1,3 @@
+module FoodsoftWiki
+ VERSION = "0.0.1"
+end
diff --git a/lib/tasks/rspec.rake b/lib/tasks/rspec.rake
index b6b58452..a7d67ae5 100644
--- a/lib/tasks/rspec.rake
+++ b/lib/tasks/rspec.rake
@@ -1,5 +1,6 @@
begin
require 'rspec/core/rake_task'
+ task(:spec).clear
RSpec::Core::RakeTask.new(:spec)
task :default => :spec
rescue LoadError
diff --git a/spec/models/article_spec.rb b/spec/models/article_spec.rb
index e3bab788..bd0d991c 100644
--- a/spec/models/article_spec.rb
+++ b/spec/models/article_spec.rb
@@ -52,4 +52,58 @@ describe Article do
order = create :order, supplier: supplier, article_ids: [article.id]
expect(article.in_open_order).to eq(order)
end
+
+
+ it 'has no shared article by default' do
+ expect(article.shared_article).to be_nil
+ end
+
+ describe 'connected to a shared database', :type => :feature do
+ let(:shared_supplier) { create(:supplier) }
+ let(:shared_article) { create :article, supplier: shared_supplier, order_number: Faker::Lorem.characters(rand(1..12)) }
+ let(:supplier) { create :supplier, shared_supplier_id: shared_supplier.id }
+ let(:article) { create :article, supplier: supplier, order_number: shared_article.order_number }
+
+ it 'can be found in the shared database' do
+ expect(article.shared_article).to_not be_nil
+ end
+
+ it 'can find updates' do
+ changed = article.shared_article_changed?
+ expect(changed).to_not be_false
+ expect(changed.length).to be > 1
+ end
+
+ it 'can be synchronised' do
+ # TODO move article sync from supplier to article
+ article # need to reference for it to exist when syncing
+ updated_article = supplier.sync_all[0].select{|s| s[0].id==article.id}.first[0]
+ article.update_attributes updated_article.attributes.reject{|k,v| k=='id' or k=='type'}
+ expect(article.name).to eq(shared_article.name)
+ # now synchronising shouldn't change anything anymore
+ expect(article.shared_article_changed?).to be_false
+ end
+
+ it 'does not need to synchronise an imported article' do
+ article = SharedArticle.find(shared_article.id).build_new_article(supplier)
+ expect(article.shared_article_changed?).to be_false
+ end
+
+ it 'adapts to foodcoop units when synchronising' do
+ shared_article.unit = '1kg'
+ shared_article.unit_quantity = 1
+ shared_article.save!
+ article = SharedArticle.find(shared_article.id).build_new_article(supplier)
+ article.article_category = create :article_category
+ article.unit = '200g'
+ article.shared_updated_on -= 1 # to make update do something
+ article.save!
+ # TODO get sync functionality in article
+ updated_article = supplier.sync_all[0].select{|s| s[0].id==article.id}.first[0]
+ article.update_attributes! updated_article.attributes.reject{|k,v| k=='id' or k=='type'}
+ expect(article.unit).to eq '200g'
+ expect(article.unit_quantity).to eq 5
+ expect(article.price).to be_within(1e-3).of(shared_article.price/5)
+ end
+ end
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index adbc4248..bba0b6b7 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -29,6 +29,8 @@ RSpec.configure do |config|
config.before(:each) do
DatabaseCleaner.strategy = (example.metadata[:js] ? :truncation : :transaction)
DatabaseCleaner.start
+ # maximise window so that buttons can be found on popups
+ example.metadata[:js] and page.driver.browser.manage.window.maximize
end
config.after(:each) do
DatabaseCleaner.clean
diff --git a/spec/support/shared_database.rb b/spec/support/shared_database.rb
new file mode 100644
index 00000000..55f8f2b3
--- /dev/null
+++ b/spec/support/shared_database.rb
@@ -0,0 +1,29 @@
+# http://stackoverflow.com/questions/8774227
+# http://blog.plataformatec.com.br/2011/12/three-tips-to-improve-the-performance-of-your-test-suite
+class ActiveRecord::Base
+ mattr_accessor :shared_connection
+ @@shared_connection = nil
+
+ def self.connection
+ @@shared_connection || retrieve_connection
+ end
+end
+# Forces all threads to share the same connection. This works on
+# Capybara because it starts the web server in a thread.
+ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
+
+ActiveSupport.on_load(:after_initialize) do
+ # We simulate the shared database by pointing to our own database.
+ # This allows running tests without additional database setup.
+ # But take care when designing tests using the shared database.
+ SharedSupplier.establish_connection Rails.env
+ SharedArticle.establish_connection Rails.env
+ # hack for different structure of shared database
+ SharedArticle.class_eval do
+ alias_attribute :number, :order_number
+ alias_attribute :updated_on, :updated_at
+ def self.find_by_number(n)
+ find_by_order_number(n)
+ end
+ end
+end
diff --git a/vendor/plugins/.gitkeep b/vendor/plugins/.gitkeep
deleted file mode 100644
index e69de29b..00000000