Class: Workarea::Order

Inherits:
Object
  • Object
show all
Includes:
ApplicationDocument, Commentable, DiscountIds, Lockable, NormalizeEmail, Queries, UrlToken
Defined in:
app/models/workarea/order.rb,
app/models/workarea/order/status.rb,
app/models/workarea/order/queries.rb,
app/models/workarea/order/fraud_decision.rb,
app/models/workarea/order/items_extension.rb

Defined Under Namespace

Modules: ItemsExtension, Queries, Status Classes: FraudDecision, Item

Instance Method Summary collapse

Methods included from Lockable

#default_lock_value, #lock!, #lock_key, #locked?, #unlock!

Methods included from Commentable

#add_subscription, #remove_subscription

Methods included from DiscountIds

#discount_ids

Methods included from ApplicationDocument

#releasable?

Methods included from Sidekiq::Callbacks

assert_valid_config!, async, disable, enable, inline, #run_callbacks

Methods included from Mongoid::Document

#embedded_children

Instance Method Details

#abandoned?Boolean

Whether this order is considered abandoned. This means not canceled or placed and not checking out within the active period.

Returns:

  • (Boolean)


311
312
313
314
# File 'app/models/workarea/order.rb', line 311

def abandoned?
  !canceled? && !placed? && !checking_out? &&
    created_at + Workarea.config.order_active_period < Time.current
end

#add_item(attributes) ⇒ Boolean

Adds an item to the order. Increases quantity if the SKU is already in the order.

Parameters:

  • attributes (Hash)

Returns:

  • (Boolean)

    success



240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'app/models/workarea/order.rb', line 240

def add_item(attributes)
  quantity = attributes.fetch(:quantity, 1).to_i
  sku = attributes[:sku]
  customizations = attributes[:customizations]

  if existing_item = items.find_existing(sku, customizations)
    update_item(existing_item.id, quantity: existing_item.quantity + quantity)
  else
    items.build(attributes)
  end

  save
end

#add_promo_code(code) ⇒ self

Adds a promo code to the order. Ensures only unique promo codes remain in the order promo code list.

Parameters:

Returns:

  • (self)


288
289
290
291
292
293
294
# File 'app/models/workarea/order.rb', line 288

def add_promo_code(code)
  promo_codes << code
  promo_codes.map!(&:upcase)
  promo_codes.uniq!
  save
  self
end

#cancelObject

Cancel this order.



341
342
343
# File 'app/models/workarea/order.rb', line 341

def cancel
  update_attribute(:canceled_at, Time.current)
end

#canceled?Boolean

Whether this order has been canceled.

Returns:

  • (Boolean)


330
331
332
# File 'app/models/workarea/order.rb', line 330

def canceled?
  !!canceled_at
end

#checking_out?Boolean

Whether this order is currently checking out, defined as whether they’ve touched checkout within Workarea.config.checkout_expiration

Returns:

  • (Boolean)


159
160
161
162
163
164
165
166
# File 'app/models/workarea/order.rb', line 159

def checking_out?
  return false unless checkout_started_at.present?

  checkout_expires_at = checkout_started_at +
                          Workarea.config.checkout_expiration

  checkout_expires_at > Time.current
end

#copied?Boolean

Whether this order was copied from another

Returns:

  • (Boolean)


335
336
337
# File 'app/models/workarea/order.rb', line 335

def copied?
  copied_from.present?
end

#fraud_suspected?Boolean

Whether this order is suspected of fraud.

Returns:

  • (Boolean)


361
362
363
# File 'app/models/workarea/order.rb', line 361

def fraud_suspected?
  !!fraud_suspected_at
end

#fulfilled_by?(*types) ⇒ Boolean

Check to see if this order delivers with any of the fulfillment policies passed in.

Parameters:

Returns:

  • (Boolean)


192
193
194
# File 'app/models/workarea/order.rb', line 192

def fulfilled_by?(*types)
  items.any? { |i| i.fulfilled_by?(*types) }
end

#has_sku?(sku) ⇒ Boolean

Whether an item of this SKU is in this order

Parameters:

Returns:

  • (Boolean)


301
302
303
# File 'app/models/workarea/order.rb', line 301

def has_sku?(sku)
  items.any? { |i| i.sku == sku }
end

#mark_as_reminded!Boolean

Mark this order as having been reminded. Used in the reminding worker to ensure an Order doesn’t get reminded twice.

Returns:

  • (Boolean)


141
142
143
144
# File 'app/models/workarea/order.rb', line 141

def mark_as_reminded!
  self.reminded_at = Time.current
  save!(validate: false)
end

#metrics_saved!Object

Mark the metrics for the order saved.



353
354
355
# File 'app/models/workarea/order.rb', line 353

def metrics_saved!
  set(metrics_saved_at: Time.current)
end

#metrics_saved?Boolean

Check whether metrics were saved for this order. Used to ensure this doesn’t happen more than once due to Sidekiq’s semantics (run at least once).

Returns:

  • (Boolean)


348
349
350
# File 'app/models/workarea/order.rb', line 348

def metrics_saved?
  !!metrics_saved_at
end

#nameString

The user-friendly name for the order

Returns:



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

def name
  I18n.t('workarea.order.name', id: id)
end

#no_items?Boolean

Whether this order is empty.

Returns:

  • (Boolean)


111
112
113
# File 'app/models/workarea/order.rb', line 111

def no_items?
  quantity == 0
end

#placeBoolean

Place the order.

Returns:

  • (Boolean)

    whether the order was placed



226
227
228
229
230
231
232
233
# File 'app/models/workarea/order.rb', line 226

def place
  return false unless purchasable?

  run_callbacks :place do
    self.placed_at = Time.current
    with(write: { w: "majority", j: true }) { save }
  end
end

#placed?Boolean

Whether this order was placed.

Returns:

  • (Boolean)


217
218
219
# File 'app/models/workarea/order.rb', line 217

def placed?
  !!placed_at
end

#price_adjustmentsPriceAdjustmentSet

All price adjustments on this order.

Returns:



103
104
105
# File 'app/models/workarea/order.rb', line 103

def price_adjustments
  PriceAdjustmentSet.new(items.map(&:price_adjustments).flatten)
end

#purchasable?Boolean

Whether this order can be purchased, which is defined here as the order having items and an email address.

Returns:

  • (Boolean)


209
210
211
# File 'app/models/workarea/order.rb', line 209

def purchasable?
  items.present? && valid?(:purchasable)
end

#quantityInteger

The number of units in this order.

Returns:

  • (Integer)


95
96
97
# File 'app/models/workarea/order.rb', line 95

def quantity
  items.select(&:valid?).sum(&:quantity)
end

#remove_item(id) ⇒ self

Removes an item from the order

Parameters:

Returns:

  • (self)


277
278
279
280
# File 'app/models/workarea/order.rb', line 277

def remove_item(id)
  items.find(id).destroy
  self
end

#requires_shipping?Boolean

Whether any of the order’s items require physical shipping.

Returns:

  • (Boolean)


200
201
202
# File 'app/models/workarea/order.rb', line 200

def requires_shipping?
  fulfilled_by?(:shipping)
end

#reset_checkout!Boolean

Clears out order checkout details, effectively placing the order back into a cart state.

Explicitly does not reset email or shipping service since these can be carried in and out of checkout.

Email can be set by being logged in or not, shipping method can be set by estimation on the cart page.

Returns:

  • (Boolean)


179
180
181
182
183
184
# File 'app/models/workarea/order.rb', line 179

def reset_checkout!
  self.user_id = nil
  self.checkout_started_at = nil
  self.token = nil
  save!
end

#set_fraud_decision!(decision) ⇒ Boolean

Sets the fraud descision for the order..

Parameters:

Returns:

  • (Boolean)


370
371
372
373
374
375
376
# File 'app/models/workarea/order.rb', line 370

def set_fraud_decision!(decision)
  update!(
    fraud_decision: decision,
    fraud_decided_at: Time.current,
    fraud_suspected_at: decision.declined? ? Time.current : nil
  )
end

#started_checkout?Boolean

Whether this order has ever started checkout

Returns:

  • (Boolean)


150
151
152
# File 'app/models/workarea/order.rb', line 150

def started_checkout?
  checkout_started_at.present?
end

#statusSymbol

Get the status of this order. Does NOT include fulfillment statuses like shipped, partially shipped, etc.

Returns:

  • (Symbol)


321
322
323
324
# File 'app/models/workarea/order.rb', line 321

def status
  calculators = Workarea.config.order_status_calculators.map(&:constantize)
  StatusCalculator.new(calculators, self).result
end

#touch_checkout!(attributes = {}) ⇒ Boolean

Update the checkout timestamp to indicate the last time this checkout was active and optionally set checkout user data

Returns:

  • (Boolean)


120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'app/models/workarea/order.rb', line 120

def touch_checkout!(attributes = {})
  update_attribute(:checkout_started_at, Time.current)
  assign_attributes(
    attributes.slice(
      :ip_address,
      :user_activity_id,
      :checkout_by_id,
      :source,
      :traffic_referrer,
      :user_agent,
      :segment_ids
    )
  )
end

#update_item(id, attributes) ⇒ Boolean

Updates an items attributes

Parameters:

  • id (String)
  • attributes (Hash)

    new item attributes

Returns:

  • (Boolean)

    whether the item was successfully updated



261
262
263
264
265
266
267
268
269
270
# File 'app/models/workarea/order.rb', line 261

def update_item(id, attributes)
  existing_item = items.find_existing(attributes[:sku], attributes[:customizations])
  if existing_item.present? && existing_item.id.to_s != id.to_s
    item = items.find(id)
    existing_item.update_attributes(quantity: existing_item.quantity + (attributes[:quantity] || item.quantity))
    item.delete
  else
    items.find(id).update_attributes(attributes)
  end
end