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:
commit
7af796c09c
47 changed files with 325 additions and 240 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue