Class: OrderArticle

Inherits:
ApplicationRecord show all
Includes:
FindEachWithOrder
Defined in:
app/models/order_article.rb

Overview

An OrderArticle represents a single Article that is part of an Order.

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#update_global_priceObject

Returns the value of attribute update_global_price


5
6
7
# File 'app/models/order_article.rb', line 5

def update_global_price
  @update_global_price
end

Instance Method Details

#calculate_units_to_order(quantity, tolerance = 0) ⇒ Object

Returns how many units of the belonging article need to be ordered given the specified order quantity and tolerance. This is determined by calculating how many units can be ordered from the given order quantity, using the tolerance to order an additional unit if the order quantity is not quiet sufficient. There must always be at least one item in a unit that is an ordered quantity (no units are ever entirely filled by tolerance items only).

Example:

unit_quantity | quantity | tolerance | calculate_units_to_order ————–----------———–+———————–

4        |    0     |     2     |           0
4        |    0     |     5     |           0
4        |    2     |     2     |           1
4        |    4     |     2     |           1
4        |    4     |     4     |           1
4        |    5     |     3     |           2
4        |    5     |     4     |           2

74
75
76
77
78
79
# File 'app/models/order_article.rb', line 74

def calculate_units_to_order(quantity, tolerance = 0)
  unit_size = price.unit_quantity
  units = quantity / unit_size
  remainder = quantity % unit_size
  units += ((remainder > 0) && (remainder + tolerance >= unit_size) ? 1 : 0)
end

#group_orders_sumObject

Count quantities of belonging group_orders. In balancing this can differ from ordered (by supplier) quantity for this article.


38
39
40
41
# File 'app/models/order_article.rb', line 38

def group_orders_sum
  quantity = group_order_articles.collect(&:result).sum
  {:quantity => quantity, :price => quantity * price.fc_price}
end

#missing_unitsNumber

Returns Units missing for the last unit_quantity of the article.

Returns:

  • (Number)

    Units missing for the last unit_quantity of the article.


190
191
192
# File 'app/models/order_article.rb', line 190

def missing_units
  _missing_units(price.unit_quantity, quantity, tolerance)
end

#missing_units_wasObject


194
195
196
# File 'app/models/order_article.rb', line 194

def missing_units_was
  _missing_units(price.unit_quantity, quantity_was, tolerance_was)
end

#ordered_quantities_different_from_group_orders?(ordered_mark = "!", billed_mark = "?", received_mark = "?") ⇒ Boolean

Returns:

  • (Boolean)

91
92
93
94
95
96
97
98
99
100
101
# File 'app/models/order_article.rb', line 91

def ordered_quantities_different_from_group_orders?(ordered_mark="!", billed_mark="?", received_mark="?")
  if not units_received.nil?
    ((units_received * price.unit_quantity) == group_orders_sum[:quantity]) ? false : received_mark
  elsif not units_billed.nil?
    ((units_billed * price.unit_quantity) == group_orders_sum[:quantity]) ? false : billed_mark
  elsif not units_to_order.nil?
    ((units_to_order * price.unit_quantity) == group_orders_sum[:quantity]) ? false : ordered_mark
  else
    nil # can happen in integration tests
  end
end

#priceObject

This method returns either the ArticlePrice or the Article The first will be set, when the the order is finished


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

def price
  article_price || article
end

#redistribute(quantity, surplus = [:tolerance], update_totals = true) ⇒ Object

redistribute articles over ordergroups

quantity       Number of units to distribute
surplus        What to do when there are more articles than ordered quantity
                 :tolerance   fill member orders' tolerance
                 :stock       move to stock
                 nil          nothing; for catching the remaining count
update_totals  Whether to update group_order and ordergroup totals

returns array with counts for each surplus method


111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'app/models/order_article.rb', line 111

def redistribute(quantity, surplus = [:tolerance], update_totals = true)
  qty_left = quantity
  counts = [0] * surplus.length

  if surplus.index(:tolerance).nil?
    qty_for_members = [qty_left, self.quantity].min
  else
    qty_for_members = [qty_left, self.quantity+self.tolerance].min
    counts[surplus.index(:tolerance)] = [0, qty_for_members-self.quantity].max
  end

  # Recompute
  group_order_articles.each {|goa| goa.save_results! qty_for_members }
  qty_left -= qty_for_members

  # if there's anything left, move to stock if wanted
  if qty_left > 0 && surplus.index(:stock)
    counts[surplus.index(:stock)] = qty_left
    # 1) find existing stock article with same name, unit, price
    # 2) if not found, create new stock article
    #      avoiding duplicate stock article names
  end
  if qty_left > 0 && surplus.index(nil)
    counts[surplus.index(nil)] = qty_left
  end

  # Update GroupOrder prices & Ordergroup stats
  # TODO only affected group_orders, and once after redistributing all articles
  if update_totals
    update_ordergroup_prices
    order.ordergroups.each(&:update_stats!)
  end

  # TODO notifications

  counts
end

#result_manually_changed?Boolean

Check if the result of any associated GroupOrderArticle was overridden manually

Returns:

  • (Boolean)

199
200
201
# File 'app/models/order_article.rb', line 199

def result_manually_changed?
  group_order_articles.any? {|goa| goa.result_manually_changed?}
end

#total_gross_priceObject

Calculate gross price for ordered qunatity.


87
88
89
# File 'app/models/order_article.rb', line 87

def total_gross_price
  units * price.unit_quantity * price.gross_price
end

#total_priceObject

Calculate price for ordered quantity.


82
83
84
# File 'app/models/order_article.rb', line 82

def total_price
  units * price.unit_quantity * price.price
end

#unitsObject

latest information on available units


30
31
32
33
34
# File 'app/models/order_article.rb', line 30

def units
  return units_received unless units_received.nil?
  return units_billed unless units_billed.nil?
  units_to_order
end

#update_article_and_price!(order_article_attributes, article_attributes, price_attributes = nil) ⇒ Object

Updates order_article and belongings during balancing process


150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'app/models/order_article.rb', line 150

def update_article_and_price!(order_article_attributes, article_attributes, price_attributes = nil)
  OrderArticle.transaction do
    # Updates self
    self.update_attributes!(order_article_attributes)

    # Updates article
    article.update_attributes!(article_attributes)

    # Updates article_price belonging to current order article
    if price_attributes.present?
      article_price.attributes = price_attributes
      if article_price.changed?
        # Updates also price attributes of article if update_global_price is selected
        if update_global_price
          article.update_attributes!(price_attributes)
          self.article_price = article.article_prices.first and save # 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
          # TODO: The price_attributes do not include an article_id so that
          #   the entry in the database will not "know" which article is
          #   referenced. Let us check the effect of that and change it or
          #   comment on the meaning.
          #   Possibly this is the real reason why the global price is not
          #   affected instead of the `created_at: order.ends` injection.
        end

        # Updates ordergroup values
        update_ordergroup_prices
      end
    end
  end
end

#update_results!Object

Update quantity/tolerance/units_to_order from group_order_articles


44
45
46
47
48
49
50
51
52
53
54
# File 'app/models/order_article.rb', line 44

def update_results!
  if order.open?
    self.quantity = group_order_articles.collect(&:quantity).sum
    self.tolerance = group_order_articles.collect(&:tolerance).sum
    self.units_to_order = calculate_units_to_order(quantity, tolerance)
    enforce_boxfill if order.boxfill?
    save!
  elsif order.finished?
    update_attribute(:units_to_order, group_order_articles.collect(&:result).sum)
  end
end