Class: Cats::Core::Stack

Inherits:
ApplicationRecord show all
Defined in:
app/models/cats/core/stack.rb

Constant Summary collapse

RESERVED =

Stack statuses

"Reserved".freeze
ALLOCATED =
"Allocated".freeze
DESTROYED =
"Destroyed".freeze
STACK_STATUSES =
[RESERVED, ALLOCATED, DESTROYED].freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.ransackable_associations(_auth_object = nil) ⇒ Object



198
199
200
201
202
203
204
205
206
# File 'app/models/cats/core/stack.rb', line 198

def self.ransackable_associations(_auth_object = nil)
  %w[
    commodity
    dispatch_transactions
    receipt_transactions
    store
    unit
  ]
end

.ransackable_attributes(_auth_object = nil) ⇒ Object



182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'app/models/cats/core/stack.rb', line 182

def self.ransackable_attributes(_auth_object = nil)
  %w[
    commodity_id
    commodity_status
    height
    length
    quantity
    stack_status
    start_x
    start_y
    store_id
    unit_id
    width
  ]
end

.search_commodity(batch_no) ⇒ Object



154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'app/models/cats/core/stack.rb', line 154

def self.search_commodity(batch_no)
  commodity = Commodity.find_by(batch_no: batch_no)
  stacks = Stack.joins(:commodity, store: :warehouse).where(
    commodity: {batch_no: batch_no},
    stack_status: Stack::ALLOCATED
  )
  stacks.map do |stack|
    {
      batch_no: batch_no,
      commodity_name: commodity.name,
      quantity: stack.quantity,
      unit: commodity.unit_abbreviation,
      location: stack.store.warehouse.name,
      location_detail: stack.store.name,
      stack: stack.code
    }
  end
end

Instance Method Details

#destroy_stackObject



173
174
175
176
177
178
179
180
# File 'app/models/cats/core/stack.rb', line 173

def destroy_stack
  unless stack_status == Cats::Core::Stack::RESERVED || quantity.zero?
    raise(StandardError, "Stack has to be either RESERVED or with zero quantity to be destroyed.")
  end

  self.stack_status = Cats::Core::Stack::DESTROYED
  save!
end

#overlaps?(st1, st2) ⇒ Boolean

A method that checks if an overlap exists b/n two stacks. An overlap b/n stacks does not occur if one of the stacks is completely above the other stack or if one of the stacks is on the left side of the other stack. If both conditions fail, it means an overlap exists b/n the two stacks

Returns:

  • (Boolean)


131
132
133
134
135
136
137
# File 'app/models/cats/core/stack.rb', line 131

def overlaps?(st1, st2)
  return false if st1.start_x > (st2.start_x + st2.length) || st2.start_x > (st1.start_x + st1.length)

  return false if st1.start_y > (st2.start_y + st2.width) || st2.start_y > (st1.start_y + st1.width)

  true
end

#stacking_rulesObject



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'app/models/cats/core/stack.rb', line 48

def stacking_rules
  rule = Cats::Core::StackingRule.first

  # If no rule is defined, then define a default rule
  rule ||= Cats::Core::StackingRule.new(
    space_between_stack: 1,
    distance_from_gangway: 2,
    distance_from_ceiling: 1,
    maximum_height: 7,
    maximum_length: 12,
    maximum_width: 12,
    distance_from_wall: 1
  )
  rule
end

#update_store_spaceObject



139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'app/models/cats/core/stack.rb', line 139

def update_store_space
  return unless length_previously_changed? || width_previously_changed? || stack_status_previously_changed?

  old_area = if length_previously_was.nil? && width_previously_was.nil?
               0
             else
               length_previously_was * width_previously_was
             end

  store.available_space += old_area
  store.available_space -= length * width unless stack_status == DESTROYED

  store.save
end

#validate_coordinatesObject



34
35
36
37
38
39
# File 'app/models/cats/core/stack.rb', line 34

def validate_coordinates
  return unless store.present? && length.present? && width.present? && start_x.present? && start_y.present?

  errors.add(:start_x, "cannot exceed length") if start_x.present? && start_x > store.length
  errors.add(:start_y, "cannot exceed width") if start_y.present? && start_y > store.width
end

#validate_dimensionsObject



41
42
43
44
45
46
# File 'app/models/cats/core/stack.rb', line 41

def validate_dimensions
  return unless store.present? && length.present? && width.present? && start_x.present? && start_y.present?

  errors.add(:length, "cannot exceed store length") if start_x + length > store.length
  errors.add(:width, "cannot exceed store width") if start_y + width > store.width
end

#validate_distance_from_ceilingObject



118
119
120
121
122
123
124
# File 'app/models/cats/core/stack.rb', line 118

def validate_distance_from_ceiling
  return unless height && store

  return unless store.height - height < stacking_rules.distance_from_ceiling

  errors.add(:height, "of stack is close to the ceiling.")
end

#validate_distance_from_wallObject



64
65
66
67
68
69
70
71
72
73
# File 'app/models/cats/core/stack.rb', line 64

def validate_distance_from_wall
  return unless store.present? && length.present? && width.present? && start_x.present? && start_y.present?

  rule = stacking_rules
  if start_x < rule.distance_from_wall || store.length - (start_x + length) < rule.distance_from_wall ||
     store.width - (start_y + width) < rule.distance_from_wall || start_y < rule.distance_from_wall
    errors.add(:base,
               message: "The stack must be placed #{rule.distance_from_wall} meter away from a store wall")
  end
end

#validate_max_heightObject



100
101
102
103
104
# File 'app/models/cats/core/stack.rb', line 100

def validate_max_height
  return unless height

  errors.add(:height, "exceeds stacking rule height.") if height > stacking_rules.maximum_height
end

#validate_max_lengthObject



106
107
108
109
110
# File 'app/models/cats/core/stack.rb', line 106

def validate_max_length
  return unless length

  errors.add(:length, "exceeds stacking rule length.") if length > stacking_rules.maximum_length
end

#validate_max_widthObject



112
113
114
115
116
# File 'app/models/cats/core/stack.rb', line 112

def validate_max_width
  return unless width

  errors.add(:width, "exceeds stacking rule width.") if width > stacking_rules.maximum_width
end

#validate_overlapObject



75
76
77
78
79
80
81
82
83
# File 'app/models/cats/core/stack.rb', line 75

def validate_overlap
  return unless store.present? && length.present? && width.present? && start_x.present? && start_y.present?

  stacks = store.stacks.where(stack_status: [RESERVED, ALLOCATED]).where.not(id: id)

  stacks.each do |s|
    errors.add(:base, message: "#{code} overlaps with #{s.code}") if overlaps?(self, s)
  end
end

#validate_space_between_stackObject



85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'app/models/cats/core/stack.rb', line 85

def validate_space_between_stack
  return unless store.present? && length.present? && width.present? && start_x.present? && start_y.present?

  stacks = store.stacks.where(stack_status: [RESERVED, ALLOCATED]).where.not(id: id)
  rule = stacking_rules
  new_stack = dup
  new_stack.assign_attributes(start_x: start_x - rule.space_between_stack,
                              start_y: start_y - rule.space_between_stack,
                              length: length + (2 * rule.space_between_stack),
                              width: width + (2 * rule.space_between_stack))
  stacks.each do |s|
    errors.add(:base, message: "#{code} overlaps with #{s.code}") if overlaps?(new_stack, s)
  end
end