2012-04-16 08:48:01 +02:00
|
|
|
# encoding: utf-8
|
|
|
|
#
|
2009-01-14 12:46:01 +01:00
|
|
|
# Ordergroups can order, they are "children" of the class Group
|
2009-01-06 11:49:19 +01:00
|
|
|
#
|
2009-01-14 12:46:01 +01:00
|
|
|
# Ordergroup have the following attributes, in addition to Group
|
2009-01-06 11:49:19 +01:00
|
|
|
# * account_balance (decimal)
|
2009-01-14 12:46:01 +01:00
|
|
|
class Ordergroup < Group
|
2012-12-16 19:03:04 +01:00
|
|
|
|
|
|
|
APPLE_MONTH_AGO = 6 # How many month back we will count tasks and orders sum
|
|
|
|
|
2009-01-29 01:57:51 +01:00
|
|
|
acts_as_paranoid # Avoid deleting the ordergroup for consistency of order-results
|
2009-08-01 13:41:22 +02:00
|
|
|
serialize :stats
|
2009-01-29 01:57:51 +01:00
|
|
|
|
2012-11-12 13:13:01 +01:00
|
|
|
has_many :financial_transactions
|
2009-01-29 01:57:51 +01:00
|
|
|
has_many :group_orders
|
2009-01-06 11:49:19 +01:00
|
|
|
has_many :orders, :through => :group_orders
|
|
|
|
|
2013-02-08 01:52:20 +01:00
|
|
|
validates_numericality_of :account_balance, :message => I18n.t('ordergroups.model.invalid_balance')
|
2013-02-24 23:26:16 +01:00
|
|
|
validate :uniqueness_of_name, :uniqueness_of_members
|
2009-01-29 01:57:51 +01:00
|
|
|
|
2009-08-01 13:41:22 +02:00
|
|
|
after_create :update_stats!
|
|
|
|
|
2009-02-02 16:35:43 +01:00
|
|
|
def contact
|
|
|
|
"#{contact_phone} (#{contact_person})"
|
|
|
|
end
|
2009-02-01 20:56:23 +01:00
|
|
|
def non_members
|
|
|
|
User.all(:order => 'nick').reject { |u| (users.include?(u) || u.ordergroup) }
|
|
|
|
end
|
2009-01-29 01:57:51 +01:00
|
|
|
|
|
|
|
def value_of_open_orders(exclude = nil)
|
2012-09-30 21:15:55 +02:00
|
|
|
group_orders.in_open_orders.reject{|go| go == exclude}.collect(&:price).sum
|
2009-01-06 11:49:19 +01:00
|
|
|
end
|
|
|
|
|
2009-01-29 01:57:51 +01:00
|
|
|
def value_of_finished_orders(exclude = nil)
|
2012-09-30 21:15:55 +02:00
|
|
|
group_orders.in_finished_orders.reject{|go| go == exclude}.collect(&:price).sum
|
2009-01-29 01:57:51 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
# Returns the available funds for this order group (the account_balance minus price of all non-closed GroupOrders of this group).
|
|
|
|
# * exclude (GroupOrder): exclude this GroupOrder from the calculation
|
|
|
|
def get_available_funds(exclude = nil)
|
|
|
|
account_balance - value_of_open_orders(exclude) - value_of_finished_orders(exclude)
|
|
|
|
end
|
|
|
|
|
2009-01-14 12:46:01 +01:00
|
|
|
# Creates a new FinancialTransaction for this Ordergroup and updates the account_balance accordingly.
|
2009-01-06 11:49:19 +01:00
|
|
|
# Throws an exception if it fails.
|
2011-06-09 21:35:05 +02:00
|
|
|
def add_financial_transaction!(amount, note, user)
|
2009-01-06 11:49:19 +01:00
|
|
|
transaction do
|
2012-08-24 14:48:53 +02:00
|
|
|
t = FinancialTransaction.new(:ordergroup => self, :amount => amount, :note => note, :user => user)
|
|
|
|
t.save!
|
2011-06-09 21:35:05 +02:00
|
|
|
self.account_balance = financial_transactions.sum('amount')
|
2009-01-06 11:49:19 +01:00
|
|
|
save!
|
2012-08-24 14:48:53 +02:00
|
|
|
# Notify only when order group had a positive balance before the last transaction:
|
|
|
|
if t.amount < 0 && self.account_balance < 0 && self.account_balance - t.amount >= 0
|
2012-12-23 17:38:04 +01:00
|
|
|
Resque.enqueue(UserNotifier, FoodsoftConfig.scope, 'negative_balance', self.id, t.id)
|
2012-08-24 14:48:53 +02:00
|
|
|
end
|
2009-01-06 11:49:19 +01:00
|
|
|
end
|
|
|
|
end
|
2009-02-04 16:41:01 +01:00
|
|
|
|
2009-08-01 13:41:22 +02:00
|
|
|
def update_stats!
|
2012-12-16 13:48:15 +01:00
|
|
|
# Get hours for every job of each user in period
|
2012-12-16 19:03:04 +01:00
|
|
|
jobs = users.sum { |u| u.tasks.done.sum(:duration, :conditions => ["updated_on > ?", APPLE_MONTH_AGO.month.ago]) }
|
2012-12-16 13:48:15 +01:00
|
|
|
# Get group_order.price for every finished order in this period
|
2012-12-16 19:03:04 +01:00
|
|
|
orders_sum = group_orders.includes(:order).merge(Order.finished).where('orders.ends >= ?', APPLE_MONTH_AGO.month.ago).sum(:price)
|
2012-12-16 13:48:15 +01:00
|
|
|
|
2012-12-16 14:13:54 +01:00
|
|
|
@readonly = false # Dirty hack, avoid getting RecordReadOnly exception when called in task after_save callback. A rails bug?
|
2009-08-01 13:41:22 +02:00
|
|
|
update_attribute(:stats, {:jobs_size => jobs, :orders_sum => orders_sum})
|
|
|
|
end
|
|
|
|
|
|
|
|
def avg_jobs_per_euro
|
|
|
|
stats[:orders_sum] != 0 ? stats[:jobs_size].to_f / stats[:orders_sum].to_f : 0
|
|
|
|
end
|
|
|
|
|
2012-06-24 21:43:36 +02:00
|
|
|
# This is the ordergroup job per euro performance
|
|
|
|
# in comparison to the hole foodcoop average
|
|
|
|
def apples
|
|
|
|
((avg_jobs_per_euro / Ordergroup.avg_jobs_per_euro) * 100).to_i rescue 0
|
|
|
|
end
|
|
|
|
|
2012-09-29 17:52:25 +02:00
|
|
|
# If the the option stop_ordering_under is set, the ordergroup is only allowed to participate in an order,
|
|
|
|
# when the apples value is above the configured amount.
|
2012-09-30 13:34:16 +02:00
|
|
|
# The restriction can be deactivated for each ordergroup.
|
2012-12-16 19:03:04 +01:00
|
|
|
# Only ordergroups, which have participated in more than 5 orders in total and more than 2 orders in apple time period
|
2012-09-29 17:52:25 +02:00
|
|
|
def not_enough_apples?
|
|
|
|
FoodsoftConfig[:stop_ordering_under].present? and
|
2012-09-30 13:34:16 +02:00
|
|
|
!ignore_apple_restriction and
|
2012-09-29 17:52:25 +02:00
|
|
|
apples < FoodsoftConfig[:stop_ordering_under] and
|
2012-12-16 19:03:04 +01:00
|
|
|
group_orders.count > 5 and
|
|
|
|
group_orders.joins(:order).merge(Order.finished).where('orders.ends >= ?', APPLE_MONTH_AGO.month.ago).count > 2
|
2012-09-29 17:52:25 +02:00
|
|
|
end
|
|
|
|
|
2009-08-01 13:41:22 +02:00
|
|
|
# Global average
|
|
|
|
def self.avg_jobs_per_euro
|
2012-12-16 13:56:47 +01:00
|
|
|
stats = Ordergroup.pluck(:stats)
|
|
|
|
stats.sum {|s| s[:jobs_size].to_f } / stats.sum {|s| s[:orders_sum].to_f }
|
2009-08-01 13:41:22 +02:00
|
|
|
end
|
2012-12-30 15:31:37 +01:00
|
|
|
|
|
|
|
def account_updated
|
|
|
|
financial_transactions.last.try(:created_on) || created_on
|
|
|
|
end
|
2009-08-01 13:41:22 +02:00
|
|
|
|
2009-02-04 16:41:01 +01:00
|
|
|
private
|
2011-06-10 13:22:15 +02:00
|
|
|
|
|
|
|
# Make sure, that a user can only be in one ordergroup
|
|
|
|
def uniqueness_of_members
|
|
|
|
users.each do |user|
|
2013-02-08 01:52:20 +01:00
|
|
|
errors.add :user_tokens, I18n.t('ordergroups.model.error_single_group', :user => user.nick) if user.groups.where(:type => 'Ordergroup').size > 1
|
2011-06-10 13:22:15 +02:00
|
|
|
end
|
|
|
|
end
|
2013-02-24 23:26:16 +01:00
|
|
|
|
|
|
|
# Make sure, the name is uniq, add usefull message if uniq group is already deleted
|
|
|
|
def uniqueness_of_name
|
|
|
|
id = new_record? ? '' : self.id
|
|
|
|
group = Ordergroup.with_deleted.where('groups.id != ? AND groups.name = ?', id, name).first
|
|
|
|
if group.present?
|
|
|
|
message = group.deleted? ? :taken_with_deleted : :taken
|
|
|
|
errors.add :name, message
|
|
|
|
end
|
|
|
|
end
|
2013-02-24 23:26:16 +01:00
|
|
|
|
|
|
|
# Make sure, the name is uniq, add usefull message if uniq group is already deleted
|
|
|
|
def uniqueness_of_name
|
|
|
|
id = new_record? ? '' : self.id
|
|
|
|
group = Ordergroup.with_deleted.where('groups.id != ? AND groups.name = ?', id, name).first
|
|
|
|
if group.present?
|
|
|
|
message = group.deleted? ? :taken_with_deleted : :taken
|
|
|
|
errors.add :name, message
|
|
|
|
end
|
|
|
|
end
|
2009-01-06 11:49:19 +01:00
|
|
|
|
|
|
|
end
|
2011-05-07 20:50:39 +02:00
|
|
|
|