Class: Ordergroup

Inherits:
Group show all
Includes:
CustomFields
Defined in:
app/models/ordergroup.rb

Overview

Ordergroups can order, they are “children” of the class Group

Ordergroup have the following attributes, in addition to Group

  • account_balance (decimal)

Constant Summary collapse

APPLE_MONTH_AGO =

How many month back we will count tasks and orders sum

6

Instance Attribute Summary

Attributes included from CustomFields

#custom_fields

Attributes inherited from Group

#user_tokens

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Group

#deleted?, #mark_as_deleted, #member?

Methods included from MarkAsDeletedWithName

#mark_as_deleted

Class Method Details

.avg_jobs_per_euroObject

Global average



147
148
149
150
151
152
153
154
# File 'app/models/ordergroup.rb', line 147

def self.avg_jobs_per_euro
  stats = Ordergroup.pluck(:stats)
  begin
    stats.sum { |s| s[:jobs_size].to_f } / stats.sum { |s| s[:orders_sum].to_f }
  rescue StandardError
    0
  end
end

.custom_fieldsObject



45
46
47
48
49
50
# File 'app/models/ordergroup.rb', line 45

def self.custom_fields
  fields = FoodsoftConfig[:custom_fields] && FoodsoftConfig[:custom_fields][:ordergroup]
  return [] unless fields

  fields.map(&:deep_symbolize_keys)
end

.include_transaction_class_sumObject



33
34
35
36
37
38
39
40
41
42
43
# File 'app/models/ordergroup.rb', line 33

def self.include_transaction_class_sum
  columns = ['groups.*']
  FinancialTransactionClass.all.find_each do |c|
    columns << "sum(CASE financial_transaction_types.financial_transaction_class_id WHEN #{c.id} THEN financial_transactions.amount ELSE 0 END) AS sum_of_class_#{c.id}"
  end

  select(columns.join(', '))
    .joins('LEFT JOIN financial_transactions ON groups.id = financial_transactions.ordergroup_id')
    .joins('LEFT JOIN financial_transaction_types ON financial_transaction_types.id = financial_transactions.financial_transaction_type_id')
    .group('groups.id')
end

.sort_by_param(param) ⇒ Object



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'app/models/ordergroup.rb', line 160

def self.sort_by_param(param)
  param ||= 'name'

  sort_param_map = {
    'name' => 'name',
    'name_reverse' => 'name DESC',
    'members_count' => 'count(users.id)',
    'members_count_reverse' => 'count(users.id) DESC',
    'last_user_activity' => 'max(users.last_activity)',
    'last_user_activity_reverse' => 'max(users.last_activity) DESC',
    'last_order' => 'max(orders.starts)',
    'last_order_reverse' => 'max(orders.starts) DESC'
  }

  result = self
  result = result.left_joins(:users).group('groups.id') if param.starts_with?('members_count', 'last_user_activity')
  result = result.left_joins(:orders).group('groups.id') if param.starts_with?('last_order')

  # Never pass user input data to Arel.sql() because of SQL Injection vulnerabilities.
  # This case here is okay, as param is mapped to the actual order string.
  result.order(Arel.sql(sort_param_map[param]))
end

Instance Method Details

#account_updatedObject



156
157
158
# File 'app/models/ordergroup.rb', line 156

def 
  financial_transactions.last.try(:updated_on) || created_on
end

#add_financial_transaction!(amount, note, user, transaction_type, link = nil, group_order = nil) ⇒ Object

Creates a new FinancialTransaction for this Ordergroup and updates the account_balance accordingly. Throws an exception if it fails.



87
88
89
90
91
92
93
94
95
96
97
# File 'app/models/ordergroup.rb', line 87

def add_financial_transaction!(amount, note, user, transaction_type, link = nil, group_order = nil)
  transaction do
    t = FinancialTransaction.new(ordergroup: self, amount: amount, note: note, user: user,
                                 financial_transaction_type: transaction_type, financial_link: link, group_order: group_order)
    t.save!
    update_balance!
    # Notify only when order group had a positive balance before the last transaction:
    NotifyNegativeBalanceJob.perform_later(self, t) if t.amount < 0 &&  < 0 &&  - t.amount >= 0
    t
  end
end

#applesObject

This is the ordergroup job per euro performance in comparison to the hole foodcoop average



127
128
129
130
131
# File 'app/models/ordergroup.rb', line 127

def apples
  ((avg_jobs_per_euro / Ordergroup.avg_jobs_per_euro) * 100).to_i
rescue StandardError
  0
end

#avg_jobs_per_euroObject



119
120
121
122
123
# File 'app/models/ordergroup.rb', line 119

def avg_jobs_per_euro
  stats[:jobs_size].to_f / stats[:orders_sum].to_f
rescue StandardError
  0
end

#contactObject



25
26
27
# File 'app/models/ordergroup.rb', line 25

def contact
  "#{contact_phone} (#{contact_person})"
end

#financial_transaction_class_balance(klass) ⇒ Object



78
79
80
81
82
83
# File 'app/models/ordergroup.rb', line 78

def financial_transaction_class_balance(klass)
  financial_transactions
    .joins(:financial_transaction_type)
    .where(financial_transaction_types: { financial_transaction_class_id: klass })
    .sum(:amount)
end

#get_available_funds(exclude = nil) ⇒ Object

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



74
75
76
# File 'app/models/ordergroup.rb', line 74

def get_available_funds(exclude = nil)
   - value_of_open_orders(exclude) - value_of_finished_orders(exclude)
end

#last_orderObject

the most recent order this ordergroup was participating in



60
61
62
# File 'app/models/ordergroup.rb', line 60

def last_order
  orders.order('orders.starts DESC').first
end

#last_user_activityObject



52
53
54
55
56
57
# File 'app/models/ordergroup.rb', line 52

def last_user_activity
  last_active_user = users.order('users.last_activity DESC').first
  return unless last_active_user

  last_active_user.last_activity
end

#non_membersObject



29
30
31
# File 'app/models/ordergroup.rb', line 29

def non_members
  User.natural_order.all.reject { |u| users.include?(u) || u.ordergroup }
end

#not_enough_apples?Boolean

If the the option stop_ordering_under is set, the ordergroup is only allowed to participate in an order, when the apples value is above the configured amount. The restriction can be deactivated for each ordergroup. Only ordergroups, which have participated in more than 5 orders in total and more than 2 orders in apple time period

Returns:

  • (Boolean)


137
138
139
140
141
142
143
144
# File 'app/models/ordergroup.rb', line 137

def not_enough_apples?
  FoodsoftConfig[:use_apple_points] &&
    FoodsoftConfig[:stop_ordering_under].present? &&
    !ignore_apple_restriction &&
    apples < FoodsoftConfig[:stop_ordering_under] &&
    group_orders.count > 5 &&
    group_orders.joins(:order).merge(Order.finished).where('orders.ends >= ?', APPLE_MONTH_AGO.month.ago).count > 2
end

#update_balance!Object



111
112
113
114
115
116
117
# File 'app/models/ordergroup.rb', line 111

def update_balance!
   = financial_transactions
                        .joins(financial_transaction_type: [:financial_transaction_class])
                        .where({ financial_transaction_classes: { ignore_for_account_balance: false } })
                        .sum(:amount)
  update_attribute :account_balance, 
end

#update_stats!Object

Recomputes job statistics from group orders.



100
101
102
103
104
105
106
107
108
109
# File 'app/models/ordergroup.rb', line 100

def update_stats!
  # Get hours for every job of each user in period
  jobs = users.to_a.sum { |u| u.tasks.done.where('updated_on > ?', APPLE_MONTH_AGO.month.ago).sum(:duration) }
  # Get group_order.price for every finished order in this period
  orders_sum = group_orders.includes(:order).merge(Order.finished).where('orders.ends >= ?',
                                                                         APPLE_MONTH_AGO.month.ago).references(:orders).sum(:price)

  @readonly = false # Dirty hack, avoid getting RecordReadOnly exception when called in task after_save callback. A rails bug?
  update_attribute(:stats, { jobs_size: jobs, orders_sum: orders_sum })
end

#value_of_finished_orders(exclude = nil) ⇒ Object



68
69
70
# File 'app/models/ordergroup.rb', line 68

def value_of_finished_orders(exclude = nil)
  group_orders.in_finished_orders.reject { |go| go == exclude }.collect(&:price).sum
end

#value_of_open_orders(exclude = nil) ⇒ Object



64
65
66
# File 'app/models/ordergroup.rb', line 64

def value_of_open_orders(exclude = nil)
  group_orders.in_open_orders.reject { |go| go == exclude }.collect(&:price).sum
end