Merge remote-tracking branch 'bennibu/rails3' into rails3

Conflicts:
	app/controllers/admin/ordergroups_controller.rb
	app/controllers/finance/balancing_controller.rb
	app/controllers/suppliers_controller.rb
	app/views/articles/_article.html.haml
	app/views/finance/balancing/_summary.haml
	app/views/finance/balancing/new.html.haml
	app/views/group_orders/_form.html.haml
	app/views/home/_apple_bar.html.haml
	app/views/suppliers/index.haml
This commit is contained in:
wvengen 2013-03-21 22:08:09 +01:00
commit 7af796c09c
47 changed files with 325 additions and 240 deletions

View File

@ -1 +0,0 @@
1.9.3-p327

View File

@ -24,7 +24,6 @@ gem 'haml-rails'
gem 'kaminari'
gem 'client_side_validations'
gem 'simple_form'
gem 'rails3_acts_as_paranoid', "~>0.2.0"
gem 'inherited_resources'
gem 'localize_input', :git => "git://github.com/bennibu/localize_input.git"
gem 'wikicloth'

View File

@ -22,32 +22,32 @@ GEM
remote: https://rubygems.org/
specs:
Ascii85 (1.0.2)
actionmailer (3.2.11)
actionpack (= 3.2.11)
mail (~> 2.4.4)
actionpack (3.2.11)
activemodel (= 3.2.11)
activesupport (= 3.2.11)
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.0)
rack (~> 1.4.5)
rack-cache (~> 1.2)
rack-test (~> 0.6.1)
sprockets (~> 2.2.1)
activemodel (3.2.11)
activesupport (= 3.2.11)
activemodel (3.2.13)
activesupport (= 3.2.13)
builder (~> 3.0.0)
activerecord (3.2.11)
activemodel (= 3.2.11)
activesupport (= 3.2.11)
activerecord (3.2.13)
activemodel (= 3.2.13)
activesupport (= 3.2.13)
arel (~> 3.0.2)
tzinfo (~> 0.3.29)
activeresource (3.2.11)
activemodel (= 3.2.11)
activesupport (= 3.2.11)
activesupport (3.2.11)
i18n (~> 0.6)
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)
@ -94,7 +94,7 @@ GEM
jquery-rails (2.1.3)
railties (>= 3.1.0, < 5.0)
thor (~> 0.14)
json (1.7.6)
json (1.7.7)
kaminari (0.14.1)
actionpack (>= 3.0.0)
activesupport (>= 3.0.0)
@ -104,7 +104,7 @@ GEM
actionpack (>= 3.1)
less (~> 2.2.0)
libv8 (3.3.10.4)
mail (2.4.4)
mail (2.5.3)
i18n (>= 0.4.0)
mime-types (~> 1.16)
treetop (~> 1.4.8)
@ -113,8 +113,8 @@ GEM
activerecord (~> 3.1)
activesupport (~> 3.1)
polyamorous (~> 0.5.0)
mime-types (1.19)
multi_json (1.5.0)
mime-types (1.21)
multi_json (1.7.1)
mysql2 (0.3.11)
pdf-reader (1.2.0)
Ascii85 (~> 1.0.0)
@ -126,34 +126,32 @@ GEM
prawn (0.12.0)
pdf-reader (>= 0.9.0)
ttfunk (~> 1.0.2)
rack (1.4.3)
rack (1.4.5)
rack-cache (1.2)
rack (>= 0.4)
rack-protection (1.3.2)
rack
rack-ssl (1.3.2)
rack-ssl (1.3.3)
rack
rack-test (0.6.2)
rack (>= 1.0)
rails (3.2.11)
actionmailer (= 3.2.11)
actionpack (= 3.2.11)
activerecord (= 3.2.11)
activeresource (= 3.2.11)
activesupport (= 3.2.11)
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.11)
rails3_acts_as_paranoid (0.2.4)
activerecord (~> 3.2)
railties (3.2.11)
actionpack (= 3.2.11)
activesupport (= 3.2.11)
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)
redis (3.0.2)
redis-namespace (1.2.1)
@ -192,8 +190,8 @@ GEM
test-unit (2.5.3)
therubyracer (0.10.2)
libv8 (~> 3.3.10)
thor (0.16.0)
tilt (1.3.3)
thor (0.17.0)
tilt (1.3.6)
treetop (1.4.12)
polyglot
polyglot (>= 0.3.1)
@ -203,7 +201,7 @@ GEM
less-rails (~> 2.2.3)
railties (>= 3.1)
therubyracer (~> 0.10.2)
tzinfo (0.3.35)
tzinfo (0.3.37)
uglifier (1.3.0)
execjs (>= 0.3.0)
multi_json (~> 1.0, >= 1.0.2)
@ -240,7 +238,6 @@ DEPENDENCIES
mysql2
prawn
rails (~> 3.2.9)
rails3_acts_as_paranoid (~> 0.2.0)
resque
ruby-prof
sass-rails (~> 3.2.3)

View File

@ -49,7 +49,7 @@ function addData(orderArticleId, itemPrice, itemUnit, itemSubtotal, itemQuantity
function increaseQuantity(item) {
var value = Number($('#q_' + item).val()) + 1;
if (!isStockit || (value <= (quantityAvailable[item] - quantityOthers[item]))) {
if (!isStockit || (value <= (quantityAvailable[item] + itemsAllocated[item]))) {
update(item, value, $('#t_' + item).val());
}
}

View File

@ -3,7 +3,7 @@ class Admin::OrdergroupsController < Admin::BaseController
inherit_resources
def index
@ordergroups = Ordergroup.order('name ASC')
@ordergroups = Ordergroup.undeleted.order('name ASC')
# if somebody uses the search field:
unless params[:query].blank?
@ -15,7 +15,7 @@ class Admin::OrdergroupsController < Admin::BaseController
def destroy
@ordergroup = Ordergroup.find(params[:id])
@ordergroup.destroy
@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')

View File

@ -20,7 +20,7 @@ class ArticlesController < ApplicationController
sort = "article_categories.name, articles.name"
end
@articles = Article.where(supplier_id: @supplier, :type => nil).includes(:article_category).order(sort)
@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?
@articles = @articles.page(params[:page]).per(@per_page)
@ -64,13 +64,13 @@ class ArticlesController < ApplicationController
# Deletes article from database. send error msg, if article is used in a current order
def destroy
@article = Article.find(params[:id])
@article.destroy unless @order = @article.in_open_order # If article is in an active Order, the Order will be returned
@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
@articles = @supplier.articles.undeleted
end
# Updates all article of specific supplier
@ -92,7 +92,7 @@ class ArticlesController < ApplicationController
end
# delete articles
if params[:outlisted_articles]
params[:outlisted_articles].keys.each {|id| Article.find(id).destroy }
params[:outlisted_articles].keys.each {|id| Article.find(id).mark_as_deleted }
end
end
# Successfully done.
@ -114,23 +114,24 @@ class ArticlesController < ApplicationController
def update_selected
raise 'Du hast keine Artikel ausgewählt' 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[:alert] = 'Keine Aktion ausgewählt!'
Article.transaction do
case params[:selected_action]
when 'destroy'
articles.each(&:mark_as_deleted)
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[:alert] = 'Keine Aktion ausgewählt!'
end
end
# action succeded
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 => "Ein Fehler ist aufgetreten: #{error}"

View File

@ -10,28 +10,30 @@ class Finance::BalancingController < Finance::BaseController
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.includes(:article).order(sort)
if params[:sort] == "order_number"
@articles = @articles.to_a.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.to_a.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
render layout: false if request.xhr?
end
def update_summary
@order = Order.find(params[:id])
end
def edit_note
@order = Order.find(params[:id])
render :layout => false
@ -55,7 +57,7 @@ class Finance::BalancingController < Finance::BaseController
def close
@order = Order.find(params[:id])
@order.close!(@current_user)
redirect_to finance_root_url, notice: t('finance.balancing.close.notice')
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)
@ -65,9 +67,9 @@ class Finance::BalancingController < Finance::BaseController
def close_direct
@order = Order.find(params[:id])
@order.close_direct!(@current_user)
redirect_to finance_balancing_url, notice: t('finance.balancing.close_direct.notice')
redirect_to finance_order_index_url, notice: t('finance.balancing.close_direct.notice')
rescue => error
redirect_to finance_balancing_url, alert: t('finance.balancing.close_direct.alert', message: error.message)
redirect_to finance_order_index_url, alert: t('finance.balancing.close_direct.alert', message: error.message)
end
end

View File

@ -26,7 +26,7 @@ class Finance::OrderArticlesController < ApplicationController
@order = Order.find(params[:order_id])
@order_article = OrderArticle.find(params[:id])
begin
@order_article.update_article_and_price!(params[:article], params[:article_price], params[:order_article])
@order_article.update_article_and_price!(params[:order_article], params[:article], params[:article_price])
rescue
render action: :edit
end

View File

@ -12,7 +12,7 @@ class Finance::OrdergroupsController < Finance::BaseController
sort = "name"
end
@ordergroups = Ordergroup.order(sort)
@ordergroups = Ordergroup.undeleted.order(sort)
@ordergroups = @ordergroups.where('name LIKE ?', "%#{params[:query]}%") unless params[:query].nil?
@ordergroups = @ordergroups.page(params[:page]).per(@per_page)

View File

@ -1,7 +1,7 @@
class Foodcoop::OrdergroupsController < ApplicationController
def index
@ordergroups = Ordergroup.order('name DESC')
@ordergroups = Ordergroup.undeleted.order('name DESC')
unless params[:name].blank? # Search by name
@ordergroups = @ordergroups.where('name LIKE ?', "%#{params[:name]}%")

View File

@ -1,7 +1,7 @@
class StockitController < ApplicationController
def index
@stock_articles = StockArticle.includes(:supplier, :article_category).
@stock_articles = StockArticle.undeleted.includes(:supplier, :article_category).
order('suppliers.name, article_categories.name, articles.name')
end
@ -33,7 +33,7 @@ class StockitController < ApplicationController
def destroy
@article = StockArticle.find(params[:id])
@article.destroy
@article.mark_as_deleted
render :layout => false
rescue => error
render :partial => "destroy_fail", :layout => false,

View File

@ -4,7 +4,7 @@ class SuppliersController < ApplicationController
helper :deliveries
def index
@suppliers = Supplier.order(:name)
@suppliers = Supplier.undeleted.order(:name)
@deliveries = Delivery.recent
end
@ -50,7 +50,7 @@ class SuppliersController < ApplicationController
def destroy
@supplier = Supplier.find(params[:id])
@supplier.destroy
@supplier.mark_as_deleted
flash[:notice] = I18n.t('suppliers.destroy.notice')
redirect_to suppliers_path
rescue => e

View File

@ -14,28 +14,26 @@ class OrderFax < OrderPdf
# From paragraph
bounding_box [margin_box.right-200,margin_box.top], width: 200 do
text FoodsoftConfig[:name], align: :right
text FoodsoftConfig[:name], size: 9, align: :right
move_down 5
text contact[:street], align: :right
text contact[:street], size: 9, align: :right
move_down 5
text "#{contact[:zip_code]} #{contact[:city]}", align: :right
text "#{contact[:zip_code]} #{contact[:city]}", size: 9, align: :right
move_down 5
if @order.supplier.customer_number != ''
text "Kundennummer: #{@order.supplier.customer_number}", align: :right
end
move_down 10
text contact[:phone], size: 9, align: :right
text "Kundennummer: #{@order.supplier.try(:customer_number)}", size: 9, align: :right
move_down 5
text contact[:email], size: 9, align: :right
text "Telefon: #{contact[:phone]}", size: 9, align: :right
move_down 5
text "E-mail: #{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.address
text @order.supplier.try(:address).to_s
move_down 5
text "Fax: " + @order.supplier.fax
text "Fax: #{@order.supplier.try(:fax)}"
end
move_down 5
@ -44,7 +42,7 @@ class OrderFax < OrderPdf
move_down 10
text "Lieferdatum:"
move_down 10
text "Ansprechpartner: " + @order.supplier.contact_person
text "Ansprechpartner: #{@order.supplier.try(:contact_person)}"
move_down 10
# Articles

View File

@ -1,6 +1,5 @@
# 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
@ -11,7 +10,8 @@ class Article < ActiveRecord::Base
belongs_to :article_category
has_many :article_prices, :order => "created_at DESC"
scope :available, :conditions => {:availability => true}
scope :undeleted, -> { where(deleted_at: nil) }
scope :available, -> { undeleted.where(availability: true) }
scope :not_in_stock, :conditions => {:type => nil}
# Validations
@ -49,6 +49,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,
@ -136,6 +141,15 @@ 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

View File

@ -8,7 +8,7 @@ class ArticleCategory < ActiveRecord::Base
protected
def check_for_associated_articles
raise I18n.t('activerecord.errors.has_many_left', collection: Article.model_name.human) if articles.exists?
raise I18n.t('activerecord.errors.has_many_left', collection: Article.model_name.human) if articles.undeleted.exists?
end
end

View File

@ -1,13 +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}
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)
@ -21,7 +23,19 @@ class Group < ActiveRecord::Base
def user_tokens=(ids)
self.user_ids = ids.split(",")
end
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

View File

@ -22,35 +22,25 @@ class GroupOrder < ActiveRecord::Base
data = {}
data[:available_funds] = ordergroup.get_available_funds(self)
unless new_record?
# Group has already ordered, so get the results...
goas = {}
group_order_articles.all.each do |goa|
goas[goa.order_article_id] = {
:quantity => goa.quantity,
:tolerance => goa.tolerance,
:quantity_result => goa.result(:quantity),
:tolerance_result => goa.result(:tolerance),
:total_price => goa.total_price
}
end
end
# load prices and other stuff....
data[:order_articles] = {}
#order.order_articles.each do |order_article|
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 => (new_record? ? 0 : goas[order_article.id][:quantity]),
:others_quantity => order_article.quantity - (new_record? ? 0 : goas[order_article.id][:quantity]),
:used_quantity => (new_record? ? 0 : goas[order_article.id][:quantity_result]),
:tolerance => (new_record? ? 0 : goas[order_article.id][:tolerance]),
:others_tolerance => order_article.tolerance - (new_record? ? 0 : goas[order_article.id][:tolerance]),
:used_tolerance => (new_record? ? 0 : goas[order_article.id][:tolerance_result]),
:total_price => (new_record? ? 0 : goas[order_article.id][:total_price]),
: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)
}

View File

@ -19,8 +19,7 @@ class Order < ActiveRecord::Base
validate :starts_before_ends, :include_articles
# Callbacks
after_update :update_price_of_group_orders
after_save :save_order_articles
after_save :save_order_articles, :update_price_of_group_orders
# Finders
scope :open, where(state: 'open').order('ends DESC')
@ -39,9 +38,11 @@ class Order < ActiveRecord::Base
def articles_for_ordering
if stockit?
# 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.all.group_by { |a| a.article_category.name }
@ -114,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
@ -215,7 +216,24 @@ class Order < ActiveRecord::Base
end
def save_order_articles
self.articles = Article.find(article_ids)
#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

View File

@ -17,6 +17,17 @@ class OrderArticle < ActiveRecord::Base
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
def price
@ -82,7 +93,7 @@ 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)
def update_article_and_price!(order_article_attributes, article_attributes, price_attributes = nil)
OrderArticle.transaction do
# Updates self
self.update_attributes!(order_article_attributes)
@ -91,20 +102,22 @@ class OrderArticle < ActiveRecord::Base
article.update_attributes!(article_attributes)
# Updates article_price belonging to current order article
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
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
# Updates ordergroup values
update_ordergroup_prices
# Updates ordergroup values
update_ordergroup_prices
end
end
end
end

View File

@ -8,7 +8,6 @@ class Ordergroup < Group
APPLE_MONTH_AGO = 6 # How many month back we will count tasks and orders sum
acts_as_paranoid # Avoid deleting the ordergroup for consistency of order-results
serialize :stats
has_many :financial_transactions
@ -120,7 +119,7 @@ class Ordergroup < Group
# 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
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

View File

@ -1,10 +1,9 @@
# encoding: utf-8
class StockArticle < Article
acts_as_paranoid
has_many :stock_changes
scope :available, :conditions => "quantity > 0"
scope :available, -> { undeleted.where'quantity > 0' }
before_destroy :check_quantity
@ -23,6 +22,11 @@ class StockArticle < Article
available.collect { |a| a.quantity * a.gross_price }.sum
end
def mark_as_deleted
check_quantity
super
end
protected
def check_quantity

View File

@ -1,7 +1,7 @@
class StockChange < ActiveRecord::Base
belongs_to :delivery
belongs_to :order
belongs_to :stock_article, with_deleted: true
belongs_to :stock_article
validates_presence_of :stock_article_id, :quantity
validates_numericality_of :quantity

View File

@ -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
@ -20,13 +20,15 @@ class Supplier < ActiveRecord::Base
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)
# also returns an array with outlisted_articles, which should be deleted
def sync_all
updated_articles = Array.new
outlisted_articles = Array.new
for article in articles
for article in articles.undeleted
# try to find the associated shared_article
shared_article = article.shared_article
@ -65,12 +67,23 @@ class Supplier < ActiveRecord::Base
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.with_deleted.where('suppliers.id != ? AND suppliers.name = ?', id, name).first
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

View File

@ -1,4 +1,4 @@
%tr{class: row_classes(article)}
%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
@ -15,5 +15,3 @@
: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'

View File

@ -25,7 +25,7 @@
%td= article.unit_quantity
%td
- logger.debug "[debug] #{article.attributes.inspect}"
- if @supplier.articles.where(order_number: article.number).exists?
- if @supplier.articles.undeleted.where(order_number: article.number).exists?
%i.icon-ok
schon importiert
- else

View File

@ -1,4 +1,4 @@
- title "Artikel von #{@supplier.name} (#{@supplier.articles.count})"
- title "Artikel von #{@supplier.name} (#{@supplier.articles.undeleted.count})"
.well.well-small
.btn-toolbar
@ -28,7 +28,7 @@
Lieferant wechseln ..
%span.caret
%ul.dropdown-menu
- Supplier.where('id != ?', @supplier.id).order('name ASC').each do |supplier|
- 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?

View File

@ -1,6 +1,6 @@
%h1 Artikel mit externer Datenbank synchronisieren
- title 'Artikel mit externer Datenbank synchronisieren'
- form_tag update_all_supplier_articles_path(@supplier, :sync => "1") do
= form_tag update_all_supplier_articles_path(@supplier, :sync => "1") do
%h2 Auslisten ...
%p
- unless @outlisted_articles.empty?
@ -25,47 +25,49 @@
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
%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 Name
%th Notiz
%th Hersteller
%th Herkunft
%th Einheit
%th GebGr
%th Preis
%th MwSt.
%th Pfand
%th Kategorie
%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)
= submit_tag 'Alle löschen/aktualisieren', class: 'btn btn-primary'
= link_to 'oder abbrechen', supplier_articles_path(@supplier)

View File

@ -10,7 +10,7 @@
= 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])
- for group_order_article in order_article.group_order_articles.select { |goa| goa.result > 0 }
%tr[group_order_article]
%td
%td{:style=>"width:50%"}

View File

@ -24,4 +24,8 @@
%td
= t('.fc_profit')
%small= t('.with_extra_charge')
%td#order_profit.numeric= number_to_currency(order.profit)
%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

View File

@ -20,7 +20,7 @@
.well.well-small
%h3= t('.comments')
#comments= render :partial => 'shared/comments', locals: {comments: @order.comments}
#comments= render :partial => 'shared/comments', locals: {comments: @order.comments.includes(:user)}
- content_for :actionbar do
.btn-group
@ -44,4 +44,4 @@
%section#results
= render 'edit_results_by_articles'
%p= link_to_top
%p= link_to_top

View File

@ -0,0 +1 @@
$('#summary').html('#{j(render('finance/balancing/summary', order: @order))}');

View File

@ -1,4 +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))}');
$('#summary').html('#{j(render('finance/balancing/summary', order: @order_article.order))}');
$('#summaryChangedWarning').show();

View File

@ -5,18 +5,20 @@
.modal-body
= form.input :units_to_order
= simple_fields_for @order_article.article do |f|
= simple_fields_for :article, @order_article.article do |f|
= f.input :name
= f.input :order_number
= f.input :unit
= simple_fields_for @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
- 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
= button_tag t('ui.close'), class: 'btn', data: {dismiss: 'modal'}
= form.submit class: 'btn btn-primary'

View File

@ -45,6 +45,8 @@
%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'
@ -66,6 +68,8 @@
- 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

View File

@ -5,4 +5,5 @@
%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]
%strong= t('.warning', threshold: FoodsoftConfig[:stop_ordering_under])
= link_to t('.more_info'), FoodsoftConfig[:applepear_url], target: '_blank'

View File

@ -0,0 +1 @@
$('#messages').html('#{j(render('messages', messages: @messages, pagination: true))}');

View File

@ -37,7 +37,7 @@
#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.order('type DESC, name ASC').all.reject { |g| g.memberships.empty? }
= 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'}

View File

@ -6,7 +6,7 @@
= t '.new_order'
%span.caret
%ul.dropdown-menu
- Supplier.all.each do |supplier|
- Supplier.undeleted.order('suppliers.name ASC').each do |supplier|
%li= link_to supplier.name, new_order_path(supplier_id: supplier.id), tabindex: -1
.well

View File

@ -8,5 +8,5 @@
= render :partial => 'page_list_item', :locals => {:page => homepage, :level => 0, :siteMap => 1}
%tbody
- for page in @pages
- if page.id != homepage.id
- if page.id != homepage.try(:id)
= render :partial => 'page_list_item', :locals => {:page => page, :level => 0, :siteMap => 1}

View File

@ -3,5 +3,5 @@
= form.hidden_field :stock_article_id
= "Menge (#{stock_change.stock_article.quantity_available})"
= form.text_field :quantity, :size => 5, :autocomplete => 'off'
%b=h truncate(stock_change.stock_article.name)
%b= stock_change.stock_article.name
= "(#{number_to_currency(stock_change.stock_article.price)} / #{stock_change.stock_article.unit})"

View File

@ -18,8 +18,8 @@
%td= link_to h(supplier.name) , supplier
%td= supplier.phone
%td= supplier.customer_number
%td= link_to t('.articles', count: supplier.articles.count), supplier_articles_path(supplier)
%td= link_to t('.stock', count: supplier.stock_articles.count), stock_articles_path
%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'

View File

@ -31,6 +31,9 @@ default: &defaults
# foodsoft documentation URL
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

View File

@ -0,0 +1,3 @@
# Increase key space for post request.
# Warning, this is dangerous. See http://stackoverflow.com/questions/12243694/getting-error-exceeded-available-parameter-key-space
Rack::Utils.key_space_limit = 262144

View File

@ -54,6 +54,8 @@ de:
fc_profit: 'FC Gewinn'
without_extra_charge: 'ohne Aufschlag:'
with_extra_charge: 'mit Aufschlag:'
changed: 'Daten wurden verändert!'
reload: 'Zusammenfassung neu laden'
orders:
name: 'Name'
end: 'Ende'

View File

@ -16,6 +16,7 @@ de:
last_update: 'Zuletzt bestellt'
funds: 'Guthaben'
name: 'Name'
supplier: 'Lieferant'
price: 'Preis'
unit: 'Einheit'
unit_missing: 'Fehlende Einheiten'

View File

@ -56,6 +56,7 @@ de:
points: 'Deine aktueller Äpfelpunktestand: %{points}'
desc: 'Abgebildet ist das Verhältnis von erledigten Aufgaben zu dem Bestellvolumen Deiner Bestellgruppe im Vergleich zum Durchschnitt in der Foodcoop. Konkret: Pro %{amount} Bestellsumme solltest Du eine Aufgabe machen!'
warning: 'Achtung, hast Du weniger als %{threshold} Äpfel, darfst Du nicht mehr bestellen!'
more_info: 'Mehr Informationen'
ordergroup:
title: 'Meine Bestellgruppe'

View File

@ -129,6 +129,7 @@ Foodsoft::Application.routes.draw do
resources :order, controller: 'balancing', path: 'balancing' do
member do
get :update_summary
get :edit_note
put :update_note